Skip to content

Commit

Permalink
fix OAS for presentation definition and client in handling correct st…
Browse files Browse the repository at this point in the history
…atus code (#3438)
  • Loading branch information
woutslakhorst authored Oct 2, 2024
1 parent 6ff1537 commit 8de5a4e
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 24 deletions.
17 changes: 4 additions & 13 deletions auth/api/iam/generated.go

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

9 changes: 6 additions & 3 deletions auth/client/iam/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@ func (hb HTTPClient) PresentationDefinition(ctx context.Context, presentationDef
var presentationDefinition pe.PresentationDefinition
err = hb.doRequest(ctx, request, &presentationDefinition)
if err != nil {
// a 404 (defined by scope) should result in a 400 for the client
// any OAuth error should be passed
// any other error should result in a 502 Bad Gateway
if httpErr, ok := err.(core.HttpError); ok && httpErr.StatusCode == 404 {
return nil, errors.Join(ErrInvalidClientCall, err)
if oauthErr, ok := err.(oauth.OAuth2Error); ok {
return nil, oauthErr
}
return nil, errors.Join(ErrBadGateway, err)
}
Expand Down Expand Up @@ -399,6 +399,9 @@ func (hb HTTPClient) doRequest(ctx context.Context, request *http.Request, targe
if ok, oauthErr := oauth.TestOAuthErrorCode(rse.ResponseBody, oauth.InvalidScope); ok {
return oauthErr
}
if ok, oauthErr := oauth.TestOAuthErrorCode(rse.ResponseBody, oauth.InvalidRequest); ok {
return oauthErr
}
return httpErr
}

Expand Down
22 changes: 22 additions & 0 deletions auth/client/iam/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,28 @@ func TestHTTPClient_PresentationDefinition(t *testing.T) {
assert.Equal(t, definition, *response)
require.NotNil(t, handler.Request)
})
t.Run("error - generic error results in 502", func(t *testing.T) {
handler := http2.Handler{StatusCode: http.StatusInternalServerError}
tlsServer, client := testServerAndClient(t, &handler)
pdUrl := test.MustParseURL(tlsServer.URL)

_, err := client.PresentationDefinition(ctx, *pdUrl)

require.Error(t, err)
assert.ErrorIs(t, err, ErrBadGateway)
})
t.Run("error - oauth error", func(t *testing.T) {
handler := http2.Handler{StatusCode: http.StatusBadRequest, ResponseData: oauth.OAuth2Error{Code: oauth.InvalidRequest}}
tlsServer, client := testServerAndClient(t, &handler)
pdUrl := test.MustParseURL(tlsServer.URL)

_, err := client.PresentationDefinition(ctx, *pdUrl)

require.Error(t, err)
oauthErr, ok := err.(oauth.OAuth2Error)
require.True(t, ok)
assert.Equal(t, oauth.InvalidRequest, oauthErr.Code)
})
}

func TestHTTPClient_AccessToken(t *testing.T) {
Expand Down
13 changes: 10 additions & 3 deletions auth/client/iam/openid4vp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"github.com/nuts-foundation/nuts-node/http/client"
test2 "github.com/nuts-foundation/nuts-node/test"
Expand Down Expand Up @@ -356,13 +357,19 @@ func TestRelyingParty_RequestRFC021AccessToken(t *testing.T) {
})
t.Run("error - failed to get presentation definition", func(t *testing.T) {
ctx := createClientServerTestContext(t)
ctx.presentationDefinition = nil
ctx.presentationDefinition = func(writer http.ResponseWriter) {
writer.Header().Add("Content-Type", "application/json")
writer.WriteHeader(http.StatusBadRequest)
bytes, _ := json.Marshal(oauth.OAuth2Error{Code: oauth.InvalidScope})
_, _ = writer.Write(bytes)
return
}

_, err := ctx.client.RequestRFC021AccessToken(context.Background(), subjectClientID, subjectID, ctx.verifierURL.String(), scopes, false, nil)

require.Error(t, err)
assert.ErrorIs(t, err, ErrInvalidClientCall)
assert.ErrorContains(t, err, "server returned HTTP 404 (expected: 200)")
assert.True(t, errors.As(err, &oauth.OAuth2Error{}))
assert.ErrorContains(t, err, string(oauth.InvalidScope))
})
t.Run("error - failed to get authorization server metadata", func(t *testing.T) {
ctx := createClientServerTestContext(t)
Expand Down
13 changes: 8 additions & 5 deletions docs/_static/auth/iam.partial.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,8 @@ paths:
summary: Used by relying parties to obtain a presentation definition for desired scopes as specified by Nuts RFC021.
description: |
The presentation definition (specified by https://identity.foundation/presentation-exchange/spec/v2.0.0/) is a JSON object that describes the desired verifiable credentials and presentation formats.
A presentation definition is matched against a wallet. If verifiable credentials matching the definition are found,
a presentation can created together with a presentation submission.
The API returns an array of definitions, one per scope/backend combination if applicable.
It returns OAuth2 errors as specified by https://www.rfc-editor.org/rfc/rfc6749.html#section-5.2, specifically: invalid_request and invalid_scope.
operationId: presentationDefinition
tags:
- oauth2
Expand Down Expand Up @@ -241,8 +240,12 @@ paths:
application/json:
schema:
"$ref": "#/components/schemas/PresentationDefinition"
"default":
$ref: '../common/error_response.yaml'
default:
description: Error response
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/oauth2/{subjectID}/response:
post:
summary: Used by wallets to post the authorization response or error to.
Expand Down

0 comments on commit 8de5a4e

Please sign in to comment.