Skip to content

Commit

Permalink
Merge 3b36cc0 into d173e0f
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Wiedemann authored Jun 3, 2024
2 parents d173e0f + 3b36cc0 commit 9a26c7a
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 28 deletions.
43 changes: 33 additions & 10 deletions api/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/JWKSet'
/services/{serviceIdentifier}/.well-known/openid-configuration:
/services/{service_id}/.well-known/openid-configuration:
get:
parameters:
- $ref: '#/components/parameters/ServiceId'
tags:
- api
operationId: VerifierAPIOpenIDConfiguration
Expand All @@ -149,20 +151,33 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/OpenIDProviderMetadata'

/info:
get:
/services/{service_id}/token:
post:
parameters:
- $ref: '#/components/parameters/ServiceId'
tags:
- base
operationId: GetBackendInfo
summary: Returns the issuer and verifier did, generated on startup
- api
operationId: GetTokenForService
summary: Token endpoint to exchange the authorization code with the actual JWT.
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/TokenRequest'
responses:
'200':
description: Object containing the info
description: The pre-generated token
content:
application/json:
schema:
$ref: '#/components/schemas/BackendInfo'
schema:
$ref: '#/components/schemas/TokenResponse'
'403':
description: Whenever something is requested that is not allowed or existent
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorMessage'

components:
parameters:
Expand Down Expand Up @@ -232,6 +247,14 @@ components:
schema:
type: string
example: packet-delivery-portal
ServiceId:
name: service_id
description: The id of the client/service that intents to start the authentication flow. Will be used to retrieve the scope and trust services to be used for verification.
in: path
required: true
schema:
type: string
example: packet-delivery-portal
schemas:
CredentialsType:
type: array
Expand Down
27 changes: 23 additions & 4 deletions openapi/api_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,33 @@ func GetToken(c *gin.Context) {
if grantType == common.TYPE_CODE {
handleTokenTypeCode(c)
} else if grantType == common.TYPE_VP_TOKEN {
handleTokenTypeVPToken(c)
handleTokenTypeVPToken(c, c.GetHeader("client_id"))
} else {
c.AbortWithStatusJSON(400, ErrorMessageUnsupportedGrantType)
}
}

func handleTokenTypeVPToken(c *gin.Context) {
// GetToken - Token endpoint to exchange the authorization code with the actual JWT.
func GetTokenForService(c *gin.Context) {

logging.Log().Debugf("%v", c.Request)
grantType, grantTypeExists := c.GetPostForm("grant_type")
if !grantTypeExists {
logging.Log().Debug("No grant_type present in the request.")
c.AbortWithStatusJSON(400, ErrorMessagNoGrantType)
return
}

if grantType == common.TYPE_CODE {
handleTokenTypeCode(c)
} else if grantType == common.TYPE_VP_TOKEN {
handleTokenTypeVPToken(c, c.Param("service_id"))
} else {
c.AbortWithStatusJSON(400, ErrorMessageUnsupportedGrantType)
}
}

func handleTokenTypeVPToken(c *gin.Context, clientId string) {
var requestBody TokenRequestBody

vpToken, vpTokenExists := c.GetPostForm("vp_token")
Expand Down Expand Up @@ -102,7 +122,6 @@ func handleTokenTypeVPToken(c *gin.Context) {
logging.Log().Warnf("Was not able to extract the credentials from the vp_token.")
return
}
clientId := c.GetHeader("client_id")

scopes := strings.Split(scope, ",")

Expand Down Expand Up @@ -270,7 +289,7 @@ func VerifierAPIJWKS(c *gin.Context) {
// VerifierAPIOpenID
func VerifierAPIOpenIDConfiguration(c *gin.Context) {

metadata, err := getApiVerifier().GetOpenIDConfiguration(c.Param("serviceIdentifier"))
metadata, err := getApiVerifier().GetOpenIDConfiguration(c.Param("service_id"))
if err != nil {
c.AbortWithStatusJSON(500, ErrorMessage{err.Error(), "Was not able to generate the OpenID metadata."})
return
Expand Down
24 changes: 12 additions & 12 deletions openapi/api_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"bytes"
"encoding/json"
"errors"
"io/ioutil"
"io"
"net/http"
"net/http/httptest"
"strings"
Expand Down Expand Up @@ -131,7 +131,7 @@ func TestGetToken(t *testing.T) {
}

if tc.expectedStatusCode == 400 {
errorBody, _ := ioutil.ReadAll(recorder.Body)
errorBody, _ := io.ReadAll(recorder.Body)
errorMessage := ErrorMessage{}
json.Unmarshal(errorBody, &errorMessage)
if errorMessage != tc.expectedError {
Expand All @@ -143,7 +143,7 @@ func TestGetToken(t *testing.T) {

tokenResponse := TokenResponse{}
if tc.expectedResponse != tokenResponse {
body, _ := ioutil.ReadAll(recorder.Body)
body, _ := io.ReadAll(recorder.Body)
err := json.Unmarshal(body, &tokenResponse)
if err != nil {
t.Errorf("%s - Was not able to unmarshal the token response. Err: %v.", tc.testName, err)
Expand Down Expand Up @@ -236,12 +236,12 @@ func TestVerifierAPIAuthenticationResponse(t *testing.T) {

tests := []test{
{"If a same-device flow is authenticated, a valid redirect should be returned.", true, "my-state", getValidVPToken(), nil, verifier.SameDeviceResponse{RedirectTarget: "http://my-verifier.org", Code: "my-code", SessionId: "my-session-id"}, 302, "http://my-verifier.org?state=my-session-id&code=my-code", ErrorMessage{}},
//{"If a cross-device flow is authenticated, a simple ok should be returned.", false, "my-state", getValidVPToken(), nil, verifier.SameDeviceResponse{}, 200, "", ErrorMessage{}},
//{"If the same-device flow responds an error, a 400 should be returend", true, "my-state", getValidVPToken(), errors.New("verification_error"), verifier.SameDeviceResponse{}, 400, "", ErrorMessage{Summary: "verification_error"}},
//{"If no state is provided, a 400 should be returned.", true, "", getValidVPToken(), nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageNoState},
//{"If an no token is provided, a 400 should be returned.", true, "my-state", "", nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageNoToken},
//{"If a token with invalid credentials is provided, a 400 should be returned.", true, "my-state", getNoVCVPToken(), nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageUnableToDecodeToken},
//{"If a token with an invalid holder is provided, a 400 should be returned.", true, "my-state", getNoHolderVPToken(), nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageUnableToDecodeToken},
{"If a cross-device flow is authenticated, a simple ok should be returned.", false, "my-state", getValidVPToken(), nil, verifier.SameDeviceResponse{}, 200, "", ErrorMessage{}},
{"If the same-device flow responds an error, a 400 should be returend", true, "my-state", getValidVPToken(), errors.New("verification_error"), verifier.SameDeviceResponse{}, 400, "", ErrorMessage{Summary: "verification_error"}},
{"If no state is provided, a 400 should be returned.", true, "", getValidVPToken(), nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageNoState},
{"If an no token is provided, a 400 should be returned.", true, "my-state", "", nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageNoToken},
{"If a token with invalid credentials is provided, a 400 should be returned.", true, "my-state", getNoVCVPToken(), nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageUnableToDecodeToken},
{"If a token with an invalid holder is provided, a 400 should be returned.", true, "my-state", getNoHolderVPToken(), nil, verifier.SameDeviceResponse{}, 400, "", ErrorMessageUnableToDecodeToken},
}

for _, tc := range tests {
Expand Down Expand Up @@ -275,7 +275,7 @@ func TestVerifierAPIAuthenticationResponse(t *testing.T) {
VerifierAPIAuthenticationResponse(testContext)

if tc.expectedStatusCode == 400 {
errorBody, _ := ioutil.ReadAll(recorder.Body)
errorBody, _ := io.ReadAll(recorder.Body)
errorMessage := ErrorMessage{}
json.Unmarshal(errorBody, &errorMessage)
if errorMessage != tc.expectedError {
Expand Down Expand Up @@ -365,7 +365,7 @@ func TestVerifierAPIStartSIOP(t *testing.T) {
}

if tc.expectedStatusCode == 400 {
errorBody, _ := ioutil.ReadAll(recorder.Body)
errorBody, _ := io.ReadAll(recorder.Body)
errorMessage := ErrorMessage{}
json.Unmarshal(errorBody, &errorMessage)
if errorMessage != tc.expectedError {
Expand All @@ -374,7 +374,7 @@ func TestVerifierAPIStartSIOP(t *testing.T) {
}
return
}
body, _ := ioutil.ReadAll(recorder.Body)
body, _ := io.ReadAll(recorder.Body)
connectionString := string(body)
if connectionString != tc.expectedConnectionString {
t.Errorf("%s - Expected connectionString %s but was %s.", tc.testName, tc.expectedConnectionString, connectionString)
Expand Down
9 changes: 8 additions & 1 deletion openapi/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ var routes = Routes{
{
"VerifierAPIOpenIDConfiguration",
http.MethodGet,
"/services/:serviceIdentifier/.well-known/openid-configuration",
"/services/:service_id/.well-known/openid-configuration",
VerifierAPIOpenIDConfiguration,
},

Expand All @@ -114,4 +114,11 @@ var routes = Routes{
"/api/v1/loginQR",
VerifierPageDisplayQRSIOP,
},

{
"GetTokenForService",
http.MethodPost,
"/services/:service_id/token",
GetTokenForService,
},
}
2 changes: 1 addition & 1 deletion verifier/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ func (v *CredentialVerifier) GetOpenIDConfiguration(serviceIdentifier string) (m
return common.OpenIDProviderMetadata{
Issuer: v.host,
AuthorizationEndpoint: v.host,
TokenEndpoint: v.host + "/token",
TokenEndpoint: v.host + "/services/" + serviceIdentifier + "/token",
JwksUri: v.host + "/.well-known/jwks",
GrantTypesSupported: []string{"authorization_code", "vp_token"},
ResponseTypesSupported: []string{"token"},
Expand Down

0 comments on commit 9a26c7a

Please sign in to comment.