Skip to content

Commit

Permalink
rename-again
Browse files Browse the repository at this point in the history
  • Loading branch information
reinkrul committed Jun 24, 2024
1 parent 5a7b902 commit 50c1a55
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 50 deletions.
10 changes: 5 additions & 5 deletions auth/api/iam/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ func (r Wrapper) HandleTokenRequest(ctx context.Context, request HandleTokenRequ
Description: "missing required parameters",
}
}
return r.handleS2SAccessTokenRequest(ctx, *ownDID, *request.Body.Scope, *request.Body.PresentationSubmission, *request.Body.Assertion)
httpRequest := ctx.Value(httpRequestContextKey{}).(*http.Request)
return r.handleS2SAccessTokenRequest(ctx, *ownDID, httpRequest.URL, *request.Body.Scope, *request.Body.PresentationSubmission, *request.Body.Assertion)
default:
return nil, oauth.OAuth2Error{
Code: oauth.UnsupportedGrantType,
Expand Down Expand Up @@ -719,16 +720,15 @@ func (r Wrapper) RequestServiceAccessToken(ctx context.Context, request RequestS
}

// resolve verifier metadata
requestVerifier, err := did.ParseDID(request.Body.Verifier)
if err != nil {
return nil, core.InvalidInputError("invalid verifier: %w", err)
if request.Body.Verifier == "" {

Check failure on line 723 in auth/api/iam/api.go

View workflow job for this annotation

GitHub Actions / Run govulncheck

request.Body.Verifier undefined (type *ServiceAccessTokenRequest has no field or method Verifier)
return nil, core.InvalidInputError("invalid verifier")
}

useDPoP := true
if request.Body.TokenType != nil && strings.EqualFold(string(*request.Body.TokenType), AccessTokenTypeBearer) {
useDPoP = false
}
tokenResult, err := r.auth.IAMClient().RequestRFC021AccessToken(ctx, *requestHolder, *requestVerifier, request.Body.Scope, useDPoP)
tokenResult, err := r.auth.IAMClient().RequestRFC021AccessToken(ctx, *requestHolder, request.Body.Verifier, request.Body.Scope, useDPoP)

Check failure on line 731 in auth/api/iam/api.go

View workflow job for this annotation

GitHub Actions / Run govulncheck

request.Body.Verifier undefined (type *ServiceAccessTokenRequest has no field or method Verifier)
if err != nil {
// this can be an internal server error, a 400 oauth error or a 412 precondition failed if the wallet does not contain the required credentials
return nil, err
Expand Down
5 changes: 4 additions & 1 deletion auth/api/iam/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions auth/api/iam/s2s_vptoken.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"time"

"github.com/nuts-foundation/go-did/did"
Expand All @@ -43,7 +44,7 @@ const s2sMaxClockSkew = 5 * time.Second

// handleS2SAccessTokenRequest handles the /token request with vp_token bearer grant type, intended for service-to-service exchanges.
// It performs cheap checks first (parameter presence and validity, matching VCs to the presentation definition), then the more expensive ones (checking signatures).
func (r Wrapper) handleS2SAccessTokenRequest(ctx context.Context, issuer did.DID, scope string, submissionJSON string, assertionJSON string) (HandleTokenRequestResponseObject, error) {
func (r Wrapper) handleS2SAccessTokenRequest(ctx context.Context, issuer did.DID, requestURL *url.URL, scope string, submissionJSON string, assertionJSON string) (HandleTokenRequestResponseObject, error) {
pexEnvelope, err := pe.ParseEnvelope([]byte(assertionJSON))
if err != nil {
return nil, oauth.OAuth2Error{
Expand All @@ -70,7 +71,7 @@ func (r Wrapper) handleS2SAccessTokenRequest(ctx context.Context, issuer did.DID
} else {
credentialSubjectID = *subjectDID
}
if err := r.validatePresentationAudience(presentation, issuer); err != nil {
if err := r.validatePresentationAudience(presentation, requestURL); err != nil {
return nil, err
}
}
Expand Down
46 changes: 23 additions & 23 deletions auth/api/iam/s2s_vptoken_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx.vcVerifier.EXPECT().VerifyVP(presentation, true, true, gomock.Any()).Return(presentation.VerifiableCredential, nil)
ctx.policy.EXPECT().PresentationDefinitions(gomock.Any(), issuerDID, requestedScope).Return(walletOwnerMapping, nil)

resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.NoError(t, err)
require.IsType(t, HandleTokenRequest200JSONResponse{}, resp)
Expand All @@ -137,7 +137,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
require.NoError(t, token.Remove(jwt.ExpirationKey))
}, verifiableCredential)

_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.EqualError(t, err, "invalid_request - presentation is missing creation or expiration date")
})
Expand All @@ -147,7 +147,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
require.NoError(t, token.Remove(jwt.NotBeforeKey))
}, verifiableCredential)

_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.EqualError(t, err, "invalid_request - presentation is missing creation or expiration date")
})
Expand All @@ -157,7 +157,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
require.NoError(t, token.Set(jwt.ExpirationKey, time.Now().Add(time.Hour)))
}, verifiableCredential)

_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.EqualError(t, err, "invalid_request - presentation is valid for too long (max 5s)")
})
Expand All @@ -169,7 +169,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx.policy.EXPECT().PresentationDefinitions(gomock.Any(), issuerDID, requestedScope).Return(walletOwnerMapping, nil)
ctx.vcVerifier.EXPECT().VerifyVP(presentation, true, true, gomock.Any()).Return(presentation.VerifiableCredential, nil)

resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.NoError(t, err)
require.IsType(t, HandleTokenRequest200JSONResponse{}, resp)
Expand All @@ -181,7 +181,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
})
t.Run("VP is not valid JSON", func(t *testing.T) {
ctx := newTestClient(t)
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, "[true, false]")
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, "[true, false]")

assert.EqualError(t, err, "invalid_request - assertion parameter is invalid: unable to parse PEX envelope as verifiable presentation: invalid JWT")
assert.Nil(t, resp)
Expand All @@ -193,7 +193,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
secondPresentation := test.CreateJSONLDPresentation(t, secondSubjectID, proofVisitor, test.JWTNutsOrganizationCredential(t, secondSubjectID))
assertionJSON, _ := json.Marshal([]VerifiablePresentation{presentation, secondPresentation})

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, string(assertionJSON))
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, string(assertionJSON))
assert.EqualError(t, err, "invalid_request - not all presentations have the same credential subject ID")
assert.Nil(t, resp)
})
Expand All @@ -203,10 +203,10 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx.vcVerifier.EXPECT().VerifyVP(presentation, true, true, gomock.Any()).Return(presentation.VerifiableCredential, nil)
ctx.policy.EXPECT().PresentationDefinitions(gomock.Any(), issuerDID, requestedScope).Return(walletOwnerMapping, nil).Times(2)

_, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, requestedScope, submissionJSON, presentation.Raw())
_, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())
require.NoError(t, err)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())
assert.EqualError(t, err, "invalid_request - presentation nonce has already been used")
assert.Nil(t, resp)
})
Expand All @@ -219,7 +219,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
})
presentation := test.CreateJSONLDPresentation(t, *subjectDID, proofVisitor, verifiableCredential)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())
assert.EqualError(t, err, "invalid_request - presentation has invalid/missing nonce")
assert.Nil(t, resp)
})
Expand All @@ -232,7 +232,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
})
presentation := test.CreateJSONLDPresentation(t, *subjectDID, proofVisitor, verifiableCredential)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())
assert.EqualError(t, err, "invalid_request - presentation has invalid/missing nonce")
assert.Nil(t, resp)
})
Expand All @@ -244,7 +244,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
_ = token.Remove("nonce")
}, verifiableCredential)

_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.EqualError(t, err, "invalid_request - presentation has invalid/missing nonce")
})
Expand All @@ -256,7 +256,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
_ = token.Set("nonce", "")
}, verifiableCredential)

_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.EqualError(t, err, "invalid_request - presentation has invalid/missing nonce")
})
Expand All @@ -268,7 +268,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
_ = token.Set("nonce", true)
}, verifiableCredential)

_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
_, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

require.EqualError(t, err, "invalid_request - presentation has invalid/missing nonce")
})
Expand All @@ -278,7 +278,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx := newTestClient(t)
presentation, _ := test.CreateJWTPresentation(t, *subjectDID, nil, verifiableCredential)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

assert.EqualError(t, err, "invalid_request - expected: did:web:example.com:iam:123, got: [] - presentation audience/domain is missing or does not match")
assert.Nil(t, resp)
Expand All @@ -289,7 +289,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
require.NoError(t, token.Set(jwt.AudienceKey, "did:example:other"))
}, verifiableCredential)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

assert.EqualError(t, err, "invalid_request - expected: did:web:example.com:iam:123, got: [did:example:other] - presentation audience/domain is missing or does not match")
assert.Nil(t, resp)
Expand All @@ -300,7 +300,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx.vcVerifier.EXPECT().VerifyVP(presentation, true, true, gomock.Any()).Return(nil, errors.New("invalid"))
ctx.policy.EXPECT().PresentationDefinitions(gomock.Any(), issuerDID, requestedScope).Return(walletOwnerMapping, nil)

resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

assert.EqualError(t, err, "invalid_request - invalid - presentation(s) or contained credential(s) are invalid")
assert.Nil(t, resp)
Expand All @@ -312,7 +312,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
CredentialSubject: []interface{}{map[string]string{}},
})

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

assert.EqualError(t, err, `invalid_request - unable to get subject DID from VC: credential subjects have no ID`)
assert.Nil(t, resp)
Expand All @@ -327,7 +327,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
}
verifiablePresentationJSON, _ := verifiablePresentation.MarshalJSON()

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, string(verifiablePresentationJSON))
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, string(verifiablePresentationJSON))

assert.EqualError(t, err, `invalid_request - presentation signer is not credential subject`)
assert.Nil(t, resp)
Expand All @@ -336,7 +336,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
t.Run("submission is not valid JSON", func(t *testing.T) {
ctx := newTestClient(t)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, "not-a-valid-submission", presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, "not-a-valid-submission", presentation.Raw())

assert.EqualError(t, err, `invalid_request - invalid presentation submission: invalid character 'o' in literal null (expecting 'u')`)
assert.Nil(t, resp)
Expand All @@ -345,7 +345,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx := newTestClient(t)
ctx.policy.EXPECT().PresentationDefinitions(gomock.Any(), issuerDID, "everything").Return(nil, policy.ErrNotFound)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, "everything", submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, "everything", submissionJSON, presentation.Raw())

assert.EqualError(t, err, `invalid_scope - not found - unsupported scope (everything) for presentation exchange: not found`)
assert.Nil(t, resp)
Expand All @@ -367,7 +367,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
ctx := newTestClient(t)
ctx.policy.EXPECT().PresentationDefinitions(gomock.Any(), issuerDID, requestedScope).Return(walletOwnerMapping, nil)

resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(context.Background(), issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())
assert.EqualError(t, err, "invalid_request - presentation submission does not conform to presentation definition (id=)")
assert.Nil(t, resp)
})
Expand All @@ -378,7 +378,7 @@ func TestWrapper_handleS2SAccessTokenRequest(t *testing.T) {
contextWithValue := context.WithValue(context.Background(), httpRequestContextKey{}, httpRequest)
ctx.policy.EXPECT().PresentationDefinitions(gomock.Any(), issuerDID, requestedScope).Return(walletOwnerMapping, nil)

resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, requestedScope, submissionJSON, presentation.Raw())
resp, err := ctx.client.handleS2SAccessTokenRequest(contextWithValue, issuerDID, nil, requestedScope, submissionJSON, presentation.Raw())

_ = assertOAuthErrorWithCode(t, err, oauth.InvalidDPopProof, "DPoP header is invalid")
assert.Nil(t, resp)
Expand Down
6 changes: 4 additions & 2 deletions auth/api/iam/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/nuts-foundation/nuts-node/policy"
"github.com/nuts-foundation/nuts-node/vcr/credential"
"github.com/nuts-foundation/nuts-node/vcr/pe"
"net/url"
)

// validatePresentationSigner checks if the presenter of the VP is the same as the subject of the VCs being presented.
Expand All @@ -51,7 +52,7 @@ func validatePresentationSigner(presentation vc.VerifiablePresentation, expected

// validatePresentationAudience checks if the presentation audience (aud claim for JWTs, domain property for JSON-LD proofs) contains the issuer DID.
// it returns an OAuth2 error if the audience is missing or does not match the issuer.
func (r Wrapper) validatePresentationAudience(presentation vc.VerifiablePresentation, issuer did.DID) error {
func (r Wrapper) validatePresentationAudience(presentation vc.VerifiablePresentation, requestURL *url.URL) error {
var audience []string
switch presentation.Format() {
case vc.JWTPresentationProofFormat:
Expand All @@ -65,8 +66,9 @@ func (r Wrapper) validatePresentationAudience(presentation vc.VerifiablePresenta
audience = []string{*proof.Domain}
}
}
issuer := requestURL.String()
for _, aud := range audience {
if aud == issuer.String() {
if aud == issuer {
return nil
}
}
Expand Down
2 changes: 1 addition & 1 deletion auth/client/iam/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type Client interface {
// PresentationDefinition returns the presentation definition from the given endpoint.
PresentationDefinition(ctx context.Context, endpoint string) (*pe.PresentationDefinition, error)
// RequestRFC021AccessToken is called by the local EHR node to request an access token from a remote Nuts node using Nuts RFC021.
RequestRFC021AccessToken(ctx context.Context, requestHolder did.DID, verifier did.DID, scopes string, useDPoP bool) (*oauth.TokenResponse, error)
RequestRFC021AccessToken(ctx context.Context, requestHolder did.DID, oauthIssuer string, scopes string, useDPoP bool) (*oauth.TokenResponse, error)

OpenIdCredentialIssuerMetadata(ctx context.Context, oauthIssuerURI string) (*oauth.OpenIDCredentialIssuerMetadata, error)

Expand Down
Loading

0 comments on commit 50c1a55

Please sign in to comment.