diff --git a/cmd/vc-rest/startcmd/start.go b/cmd/vc-rest/startcmd/start.go index 10882d422..3ab47bf48 100644 --- a/cmd/vc-rest/startcmd/start.go +++ b/cmd/vc-rest/startcmd/start.go @@ -846,9 +846,9 @@ func buildEchoHandler( })) oidc4vpv1.RegisterHandlers(e, oidc4vpv1.NewController(&oidc4vpv1.Config{ - DefaultHTTPClient: getHTTPClient(metricsProvider.ClientOIDC4PV1), - ExternalHostURL: conf.StartupParameters.hostURLExternal, // use host external as this url will be called internally - Tracer: conf.Tracer, + HTTPClient: getHTTPClient(metricsProvider.ClientOIDC4PV1), + ExternalHostURL: conf.StartupParameters.hostURLExternal, // use host external as this url will be called internally + Tracer: conf.Tracer, })) issuerv1.RegisterHandlers(e, issuerv1.NewController(&issuerv1.Config{ @@ -945,19 +945,19 @@ func buildEchoHandler( var oidc4vpService oidc4vp.ServiceInterface oidc4vpService = oidc4vp.NewService(&oidc4vp.Config{ - EventSvc: eventSvc, - EventTopic: conf.StartupParameters.verifierEventTopic, - TransactionManager: oidc4vpTxManager, - RequestObjectPublicStore: requestObjectStoreService, - KMSRegistry: kmsRegistry, - VDR: conf.VDR, - DocumentLoader: documentLoader, - ProfileService: verifierProfileSvc, - PresentationVerifier: verifyPresentationSvc, - TrustRegistry: trustRegistryService, - RedirectURL: conf.StartupParameters.apiGatewayURL + oidc4VPCheckEndpoint, - TokenLifetime: 15 * time.Minute, - Metrics: metrics, + EventSvc: eventSvc, + EventTopic: conf.StartupParameters.verifierEventTopic, + TransactionManager: oidc4vpTxManager, + RequestObjectStore: requestObjectStoreService, + KMSRegistry: kmsRegistry, + VDR: conf.VDR, + DocumentLoader: documentLoader, + ProfileService: verifierProfileSvc, + PresentationVerifier: verifyPresentationSvc, + TrustRegistry: trustRegistryService, + RedirectURL: conf.StartupParameters.apiGatewayURL + oidc4VPCheckEndpoint, + TokenLifetime: 15 * time.Minute, + Metrics: metrics, }) if conf.IsTraceEnabled { diff --git a/component/wallet-cli/pkg/oidc4vp/models.go b/component/wallet-cli/pkg/oidc4vp/models.go index 2dbd506ba..7d23c41a8 100644 --- a/component/wallet-cli/pkg/oidc4vp/models.go +++ b/component/wallet-cli/pkg/oidc4vp/models.go @@ -14,37 +14,25 @@ import ( ) type RequestObject struct { - JTI string `json:"jti"` - IAT int64 `json:"iat"` - ResponseType string `json:"response_type"` - ResponseMode string `json:"response_mode"` - Scope string `json:"scope"` - Nonce string `json:"nonce"` - ClientID string `json:"client_id"` - RedirectURI string `json:"redirect_uri"` - State string `json:"state"` - Exp int64 `json:"exp"` - Registration RequestObjectRegistration `json:"registration"` - Claims RequestObjectClaims `json:"claims"` + JTI string `json:"jti"` + IAT int64 `json:"iat"` + ResponseType string `json:"response_type"` + ResponseMode string `json:"response_mode"` + Scope string `json:"scope"` + Nonce string `json:"nonce"` + ClientID string `json:"client_id"` + RedirectURI string `json:"redirect_uri"` + State string `json:"state"` + Exp int64 `json:"exp"` + ClientMetadata *ClientMetadata `json:"client_metadata"` + PresentationDefinition *presexch.PresentationDefinition `json:"presentation_definition"` } -type RequestObjectRegistration struct { +type ClientMetadata struct { ClientName string `json:"client_name"` + ClientPurpose string `json:"client_purpose"` SubjectSyntaxTypesSupported []string `json:"subject_syntax_types_supported"` VPFormats *presexch.Format `json:"vp_formats"` - ClientPurpose string `json:"client_purpose"` -} - -type RequestObjectClaims struct { - VPToken VPToken `json:"vp_token"` -} - -type VPToken struct { - PresentationDefinition *presexch.PresentationDefinition `json:"presentation_definition"` -} - -type IDTokenVPToken struct { - PresentationSubmission *presexch.PresentationSubmission `json:"presentation_submission"` } type Claims = map[string]interface{} @@ -52,7 +40,6 @@ type Claims = map[string]interface{} type IDTokenClaims struct { // ScopeAdditionalClaims stores claims retrieved using custom scope. ScopeAdditionalClaims map[string]Claims `json:"_scope,omitempty"` //custom scope -> additional claims - VPToken IDTokenVPToken `json:"_vp_token"` AttestationVP string `json:"_attestation_vp"` Nonce string `json:"nonce"` Exp int64 `json:"exp"` diff --git a/component/wallet-cli/pkg/oidc4vp/oidc4vp_flow.go b/component/wallet-cli/pkg/oidc4vp/oidc4vp_flow.go index d0f2d450e..63b9f0795 100644 --- a/component/wallet-cli/pkg/oidc4vp/oidc4vp_flow.go +++ b/component/wallet-cli/pkg/oidc4vp/oidc4vp_flow.go @@ -183,7 +183,7 @@ func (f *Flow) Run(ctx context.Context) error { if err = copier.CopyWithOption( &pd, - requestObject.Claims.VPToken.PresentationDefinition, + requestObject.PresentationDefinition, copier.Option{IgnoreEmpty: true, DeepCopy: true}, ); err != nil { return fmt.Errorf("copy presentation definition: %w", err) @@ -191,7 +191,7 @@ func (f *Flow) Run(ctx context.Context) error { if f.disableSchemaValidation && len(pd.InputDescriptors) > 0 { pd.InputDescriptors[0].Schema = nil - requestObject.Claims.VPToken.PresentationDefinition.InputDescriptors[0].Schema = nil + requestObject.PresentationDefinition.InputDescriptors[0].Schema = nil } vp, err := f.queryWallet(&pd) @@ -412,7 +412,7 @@ func (f *Flow) sendAuthorizationResponse( return fmt.Errorf("missing or invalid presentation_submission") } - vpFormats := requestObject.Registration.VPFormats + vpFormats := requestObject.ClientMetadata.VPFormats for i := range presentationSubmission.DescriptorMap { if vpFormats.JwtVP != nil { @@ -429,7 +429,6 @@ func (f *Flow) sendAuthorizationResponse( idToken, err := f.createIDToken( ctx, - presentationSubmission, requestObject.ClientID, requestObject.Nonce, requestObject.Scope, attestationRequired, ) @@ -437,10 +436,16 @@ func (f *Flow) sendAuthorizationResponse( return fmt.Errorf("create id token: %w", err) } + presentationSubmissionJSON, err := json.Marshal(presentationSubmission) + if err != nil { + return fmt.Errorf("marshal presentation submission: %w", err) + } + v := url.Values{ - "id_token": {idToken}, - "vp_token": {vpToken}, - "state": {requestObject.State}, + "id_token": {idToken}, + "vp_token": {vpToken}, + "presentation_submission": {string(presentationSubmissionJSON)}, + "state": {requestObject.State}, } f.perfInfo.CreateAuthorizedResponse = time.Since(start) @@ -459,7 +464,7 @@ func (f *Flow) createVPToken( return "", fmt.Errorf("get subject did: %w", err) } - vpFormats := requestObject.Registration.VPFormats + vpFormats := requestObject.ClientMetadata.VPFormats switch { case vpFormats.JwtVP != nil: @@ -599,7 +604,6 @@ func (f *Flow) signPresentationLDP( func (f *Flow) createIDToken( ctx context.Context, - presentationSubmission *presexch.PresentationSubmission, clientID, nonce, requestObjectScope string, attestationRequired bool, ) (string, error) { @@ -610,17 +614,14 @@ func (f *Flow) createIDToken( idToken := &IDTokenClaims{ ScopeAdditionalClaims: scopeAdditionalClaims, - VPToken: IDTokenVPToken{ - PresentationSubmission: presentationSubmission, - }, - Nonce: nonce, - Exp: time.Now().Unix() + tokenLifetimeSeconds, - Iss: "https://self-issued.me/v2/openid-vc", - Aud: clientID, - Sub: f.walletDID.String(), - Nbf: time.Now().Unix(), - Iat: time.Now().Unix(), - Jti: uuid.NewString(), + Nonce: nonce, + Exp: time.Now().Unix() + tokenLifetimeSeconds, + Iss: "https://self-issued.me/v2/openid-vc", + Aud: clientID, + Sub: f.walletDID.String(), + Nbf: time.Now().Unix(), + Iat: time.Now().Unix(), + Jti: uuid.NewString(), } if attestationRequired { diff --git a/pkg/internal/testutil/jwt.go b/pkg/internal/testutil/jwt.go index 407c1f952..1aaafe507 100644 --- a/pkg/internal/testutil/jwt.go +++ b/pkg/internal/testutil/jwt.go @@ -52,10 +52,14 @@ func SignedClaimsJWT(t *testing.T, claims interface{}) *SignedClaimsJWTResult { algName, err := jwsAlgo.Name() require.NoError(t, err) - token, err := jwt.NewSigned(claims, jwt.SignParameters{ - KeyID: didDoc.VerificationMethod[0].ID, - JWTAlg: algName, - }, creator.New(creator.WithJWTAlg(eddsa.New(), fks))) + token, err := jwt.NewSigned( + claims, + jwt.SignParameters{ + KeyID: didDoc.VerificationMethod[0].ID, + JWTAlg: algName, + }, + creator.New(creator.WithJWTAlg(eddsa.New(), fks)), + ) require.NoError(t, err) jws, err := token.Serialize(false) @@ -85,10 +89,14 @@ func SignedClaimsJWTWithExistingPrivateKey( algName, err := jwsAlgo.Name() require.NoError(t, err) - token, err := jwt.NewSigned(claims, jwt.SignParameters{ - KeyID: verMethodDIDKeyID, - JWTAlg: algName, - }, creator.New(creator.WithJWTAlg(eddsa.New(), signer))) + token, err := jwt.NewSigned( + claims, + jwt.SignParameters{ + KeyID: verMethodDIDKeyID, + JWTAlg: algName, + }, + creator.New(creator.WithJWTAlg(eddsa.New(), signer)), + ) require.NoError(t, err) jws, err := token.Serialize(false) diff --git a/pkg/restapi/v1/oidc4vp/controller.go b/pkg/restapi/v1/oidc4vp/controller.go index 8edb96793..4b7d443ad 100644 --- a/pkg/restapi/v1/oidc4vp/controller.go +++ b/pkg/restapi/v1/oidc4vp/controller.go @@ -32,52 +32,55 @@ type HTTPClient interface { // Config holds configuration options for Controller. type Config struct { - DefaultHTTPClient HTTPClient - ExternalHostURL string - Tracer trace.Tracer + HTTPClient HTTPClient + ExternalHostURL string + Tracer trace.Tracer } // Controller for OIDC credential issuance API. type Controller struct { - defaultHTTPClient HTTPClient - internalHostURL string - tracer trace.Tracer + httpClient HTTPClient + internalHostURL string + tracer trace.Tracer } // NewController creates a new Controller instance. func NewController(config *Config) *Controller { return &Controller{ - defaultHTTPClient: config.DefaultHTTPClient, - internalHostURL: config.ExternalHostURL, - tracer: config.Tracer, + httpClient: config.HTTPClient, + internalHostURL: config.ExternalHostURL, + tracer: config.Tracer, } } // PresentAuthorizationResponse (POST /oidc/present). func (c *Controller) PresentAuthorizationResponse(e echo.Context) error { - req := e.Request() + request := e.Request() - ctx, span := c.tracer.Start(req.Context(), "PresentAuthorizationResponse") + ctx, span := c.tracer.Start(request.Context(), "PresentAuthorizationResponse") defer span.End() - req, err := http.NewRequestWithContext(ctx, http.MethodPost, - c.internalHostURL+oidc4VPCheckEndpoint, req.Body) + req, err := http.NewRequestWithContext(ctx, + http.MethodPost, + c.internalHostURL+oidc4VPCheckEndpoint, + request.Body, + ) if err != nil { - return err + return fmt.Errorf("failed to create request: %w", err) } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - resp, err := c.defaultHTTPClient.Do(req) + resp, err := c.httpClient.Do(req) if err != nil { - return err + return fmt.Errorf("failed to send request: %w", err) } defer closeResponseBody(e.Request().Context(), resp.Body) respBytes, err := io.ReadAll(resp.Body) if err != nil { - return err + return fmt.Errorf("failed to read response body: %w", err) } if resp.StatusCode != http.StatusOK { diff --git a/pkg/restapi/v1/oidc4vp/controller_test.go b/pkg/restapi/v1/oidc4vp/controller_test.go index c87c5e29a..7ccfe364c 100644 --- a/pkg/restapi/v1/oidc4vp/controller_test.go +++ b/pkg/restapi/v1/oidc4vp/controller_test.go @@ -9,6 +9,7 @@ package oidc4vp_test import ( "bytes" + "errors" "io" "net/http" "net/http/httptest" @@ -33,19 +34,53 @@ func TestController_OidcPresent(t *testing.T) { { name: "success", setup: func() { - mockHTTPClient.EXPECT().Do(gomock.Any()).Return(&http.Response{StatusCode: http.StatusOK, - Body: io.NopCloser(bytes.NewBuffer(nil))}, nil) + mockHTTPClient.EXPECT().Do(gomock.Any()).Return( + &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewBuffer(nil)), + }, nil, + ) }, check: func(t *testing.T, rec *httptest.ResponseRecorder, err error) { require.NoError(t, err) require.Equal(t, http.StatusOK, rec.Code) }, }, + { + name: "fail to send request", + setup: func() { + mockHTTPClient.EXPECT().Do(gomock.Any()).Return( + nil, + errors.New("do request error"), + ) + }, + check: func(t *testing.T, rec *httptest.ResponseRecorder, err error) { + require.ErrorContains(t, err, "failed to send request") + }, + }, + { + name: "fail to read response body", + setup: func() { + mockHTTPClient.EXPECT().Do(gomock.Any()).Return( + &http.Response{ + StatusCode: http.StatusInternalServerError, + Body: io.NopCloser(&failReader{}), + }, nil, + ) + }, + check: func(t *testing.T, rec *httptest.ResponseRecorder, err error) { + require.ErrorContains(t, err, "failed to read response body") + }, + }, { name: "fail to present", setup: func() { - mockHTTPClient.EXPECT().Do(gomock.Any()).Return(&http.Response{StatusCode: http.StatusInternalServerError, - Body: io.NopCloser(bytes.NewBuffer([]byte("error check id token")))}, nil) + mockHTTPClient.EXPECT().Do(gomock.Any()).Return( + &http.Response{ + StatusCode: http.StatusInternalServerError, + Body: io.NopCloser(bytes.NewBuffer([]byte("error check id token"))), + }, nil, + ) }, check: func(t *testing.T, rec *httptest.ResponseRecorder, err error) { require.ErrorContains(t, err, "error check id token") @@ -57,8 +92,8 @@ func TestController_OidcPresent(t *testing.T) { tt.setup() controller := oidc4vp.NewController(&oidc4vp.Config{ - DefaultHTTPClient: mockHTTPClient, - Tracer: trace.NewNoopTracerProvider().Tracer(""), + HTTPClient: mockHTTPClient, + Tracer: trace.NewNoopTracerProvider().Tracer(""), }) req := httptest.NewRequest(http.MethodGet, "/", http.NoBody) @@ -71,3 +106,9 @@ func TestController_OidcPresent(t *testing.T) { }) } } + +type failReader struct{} + +func (f *failReader) Read([]byte) (int, error) { + return 0, errors.New("read error") +} diff --git a/pkg/restapi/v1/verifier/controller.go b/pkg/restapi/v1/verifier/controller.go index e51b431a7..c361c1412 100644 --- a/pkg/restapi/v1/verifier/controller.go +++ b/pkg/restapi/v1/verifier/controller.go @@ -61,20 +61,15 @@ var ( ) type rawAuthorizationResponse struct { - IDToken string - VPToken []string - State string -} - -type IDTokenVPToken struct { - // TODO: use *presexch.PresentationSubmission instead of map[string]interface{} - PresentationSubmission map[string]interface{} `json:"presentation_submission"` + IDToken string + VPToken []string + PresentationSubmission string + State string } type IDTokenClaims struct { // CustomScopeClaims stores claims retrieved using custom scope. CustomScopeClaims map[string]oidc4vp.Claims `json:"_scope,omitempty"` - VPToken IDTokenVPToken `json:"_vp_token"` AttestationVP string `json:"_attestation_vp"` Nonce string `json:"nonce"` Aud string `json:"aud"` @@ -82,11 +77,13 @@ type IDTokenClaims struct { } type VPTokenClaims struct { - Nonce string - Aud string - SignerDIDID string - VpTokenFormat vcsverifiable.Format - VP *verifiable.Presentation + Nonce string `json:"nonce"` + Aud string `json:"aud"` + Iss string `json:"iss"` + Exp int64 `json:"exp"` + SignerDIDID string `json:"signer_did_id"` + VpTokenFormat vcsverifiable.Format `json:"vp_token_format"` + VP *verifiable.Presentation `json:"vp"` } type PresentationDefinition = json.RawMessage @@ -460,17 +457,16 @@ func (c *Controller) CheckAuthorizationResponse(e echo.Context) error { return err } - authorisationResponseParsed, err := c.verifyAuthorizationResponseTokens(ctx, rawAuthResp) + responseParsed, err := c.verifyAuthorizationResponseTokens(ctx, rawAuthResp) if err != nil { - if tenantID, e := util.GetTenantIDFromRequest(e); e == nil { + if tenantID, authErr := util.GetTenantIDFromRequest(e); authErr == nil { c.sendFailedEvent(ctx, rawAuthResp.State, tenantID, "", "", err) } return err } - err = c.oidc4VPService.VerifyOIDCVerifiablePresentation( - ctx, oidc4vp.TxID(rawAuthResp.State), authorisationResponseParsed) + err = c.oidc4VPService.VerifyOIDCVerifiablePresentation(ctx, oidc4vp.TxID(rawAuthResp.State), responseParsed) if err != nil { return err } @@ -565,11 +561,24 @@ func (c *Controller) verifyAuthorizationResponseTokens( logger.Debugc(ctx, "validateResponseAuthTokens", log.WithDuration(time.Since(startTime))) }() - idTokenClaims, err := validateIDToken(authResp.IDToken, c.proofChecker) + var presentationSubmission map[string]interface{} + + if authResp.PresentationSubmission != "" { + if err := json.Unmarshal([]byte(authResp.PresentationSubmission), &presentationSubmission); err != nil { + return nil, resterr.NewValidationError(resterr.InvalidValue, "presentation_submission", err) + } + } + + idTokenClaims, err := validateIDToken(authResp.IDToken, &presentationSubmission, c.proofChecker) if err != nil { return nil, err } + if presentationSubmission == nil { + return nil, resterr.NewValidationError(resterr.InvalidValue, "presentation_submission", + fmt.Errorf("presentation_submission is missed")) + } + logger.Debugc(ctx, "CheckAuthorizationResponse id_token verified") var processedVPTokens []*oidc4vp.ProcessedVPToken @@ -603,15 +612,17 @@ func (c *Controller) verifyAuthorizationResponseTokens( vpTokenClaims.VP.Context = append(vpTokenClaims.VP.Context, presexch.PresentationSubmissionJSONLDContextIRI) vpTokenClaims.VP.Type = append(vpTokenClaims.VP.Type, presexch.PresentationSubmissionJSONLDType) - vpTokenClaims.VP.CustomFields[vpSubmissionProperty] = idTokenClaims.VPToken.PresentationSubmission - - processedVPTokens = append(processedVPTokens, &oidc4vp.ProcessedVPToken{ - Nonce: idTokenClaims.Nonce, - ClientID: idTokenClaims.Aud, - VpTokenFormat: vpTokenClaims.VpTokenFormat, - Presentation: vpTokenClaims.VP, - SignerDIDID: vpTokenClaims.SignerDIDID, - }) + vpTokenClaims.VP.CustomFields[vpSubmissionProperty] = presentationSubmission + + processedVPTokens = append(processedVPTokens, + &oidc4vp.ProcessedVPToken{ + Nonce: idTokenClaims.Nonce, + ClientID: idTokenClaims.Aud, + VpTokenFormat: vpTokenClaims.VpTokenFormat, + Presentation: vpTokenClaims.VP, + SignerDIDID: vpTokenClaims.SignerDIDID, + }, + ) } return &oidc4vp.AuthorizationResponseParsed{ @@ -621,59 +632,62 @@ func (c *Controller) verifyAuthorizationResponseTokens( }, nil } -func validateIDToken(idToken string, verifier jwt.ProofChecker) (*IDTokenClaims, error) { - _, rawClaims, err := jwt.ParseAndCheckProof(idToken, - verifier, false, +func validateIDToken( + idTokenJWT string, + presentationSubmission *map[string]interface{}, + verifier jwt.ProofChecker, +) (*IDTokenClaims, error) { + _, rawClaims, err := jwt.ParseAndCheckProof( + idTokenJWT, + verifier, + false, jwt.WithIgnoreClaimsMapDecoding(true), ) if err != nil { return nil, resterr.NewValidationError(resterr.InvalidValue, "id_token", err) } - var fastParser fastjson.Parser - v, err := fastParser.ParseBytes(rawClaims) - if err != nil { - return nil, fmt.Errorf("decode claims: %w", err) - } + var parser fastjson.Parser - var presentationSubmission map[string]interface{} - sb, err := v.Get("_vp_token", "presentation_submission").Object() - if err == nil { - if err = json.Unmarshal(sb.MarshalTo([]byte{}), &presentationSubmission); err != nil { - return nil, fmt.Errorf("decode presentation_submission: %w", err) - } + v, err := parser.ParseBytes(rawClaims) + if err != nil { + return nil, fmt.Errorf("decode id_token claims: %w", err) } var customScopeClaims map[string]oidc4vp.Claims + if val := v.Get("_scope"); val != nil { - sb, err = val.Object() + var obj *fastjson.Object + + obj, err = val.Object() if err == nil { - if err = json.Unmarshal(sb.MarshalTo([]byte{}), &customScopeClaims); err != nil { + if err = json.Unmarshal(obj.MarshalTo([]byte{}), &customScopeClaims); err != nil { return nil, fmt.Errorf("decode _scope: %w", err) } } } + if val := v.Get("_vp_token", "presentation_submission"); val != nil { // _vp_token is obsolete + var obj *fastjson.Object + + obj, err = v.Get("_vp_token", "presentation_submission").Object() + if err == nil { + if err = json.Unmarshal(obj.MarshalTo([]byte{}), &presentationSubmission); err != nil { + return nil, fmt.Errorf("decode presentation_submission: %w", err) + } + } + } + idTokenClaims := &IDTokenClaims{ CustomScopeClaims: customScopeClaims, - VPToken: IDTokenVPToken{ - PresentationSubmission: presentationSubmission, - }, - AttestationVP: string(v.GetStringBytes("_attestation_vp")), - Nonce: string(v.GetStringBytes("nonce")), - Aud: string(v.GetStringBytes("aud")), - Exp: v.GetInt64("exp"), + AttestationVP: string(v.GetStringBytes("_attestation_vp")), + Nonce: string(v.GetStringBytes("nonce")), + Aud: string(v.GetStringBytes("aud")), + Exp: v.GetInt64("exp"), } if idTokenClaims.Exp < time.Now().Unix() { - return nil, resterr.NewValidationError(resterr.InvalidValue, "id_token.exp", fmt.Errorf( - "token expired")) - } - - if idTokenClaims.VPToken.PresentationSubmission == nil { - return nil, resterr.NewValidationError(resterr.InvalidValue, - "id_token._vp_token.presentation_submission", fmt.Errorf( - "$_vp_token.presentation_submission is missed")) + return nil, resterr.NewValidationError(resterr.InvalidValue, "id_token.exp", fmt.Errorf("token expired")) } return idTokenClaims, nil @@ -695,16 +709,16 @@ func (c *Controller) validateVPTokenJWT(vpToken string) (*VPTokenClaims, error) return nil, resterr.NewValidationError(resterr.InvalidValue, "vp_token", err) } - var fastParser fastjson.Parser - v, err := fastParser.ParseBytes(rawClaims) + var parser fastjson.Parser + v, err := parser.ParseBytes(rawClaims) if err != nil { - return nil, fmt.Errorf("decode claims: %w", err) + return nil, fmt.Errorf("decode vp token claims: %w", err) } exp := v.GetInt64("exp") if exp < time.Now().Unix() { - return nil, resterr.NewValidationError(resterr.InvalidValue, "vp_token.exp", fmt.Errorf( - "token expired")) + return nil, resterr.NewValidationError(resterr.InvalidValue, "vp_token.exp", + fmt.Errorf("token expired")) } presentation, err := verifiable.ParsePresentation([]byte(vpToken), @@ -714,7 +728,7 @@ func (c *Controller) validateVPTokenJWT(vpToken string) (*VPTokenClaims, error) return nil, resterr.NewValidationError(resterr.InvalidValue, "vp_token.vp", err) } - // Do not need to check since is has passed jwt.Parse(). + // Do not need to check err since token has passed jwt.Parse(). kid, _ := jsonWebToken.Headers.KeyID() return &VPTokenClaims{ @@ -766,14 +780,16 @@ func (c *Controller) validateVPTokenLDP(vpToken string) (*VPTokenClaims, error) func validateAuthorizationResponse(ctx echo.Context) (*rawAuthorizationResponse, error) { startTime := time.Now().UTC() + defer func() { - logger.Debugc(ctx.Request().Context(), - "validateAuthorizationResponse", log.WithDuration(time.Since(startTime))) + logger.Debugc(ctx.Request().Context(), "validateAuthorizationResponse", log.WithDuration(time.Since(startTime))) }() + req := ctx.Request() - headerContentType := req.Header.Get("Content-Type") - if headerContentType != "application/x-www-form-urlencoded" { + contentType := req.Header.Get("Content-Type") + + if contentType != "application/x-www-form-urlencoded" { return nil, fmt.Errorf("content type is not application/x-www-form-urlencoded") } @@ -789,8 +805,8 @@ func validateAuthorizationResponse(ctx echo.Context) (*rawAuthorizationResponse, return nil, err } - logger.Debugc(ctx.Request().Context(), - "AuthorizationResponse id_token decoded", logfields.WithIDToken(res.IDToken)) + logger.Debugc(ctx.Request().Context(), "AuthorizationResponse id_token decoded", + logfields.WithIDToken(res.IDToken)) var vpTokenStr string @@ -803,6 +819,16 @@ func validateAuthorizationResponse(ctx echo.Context) (*rawAuthorizationResponse, logger.Debugc(ctx.Request().Context(), "AuthorizationResponse vp_token decoded") + if req.PostForm.Has("presentation_submission") { + err = decodeFormValue(&res.PresentationSubmission, "presentation_submission", req.PostForm) + if err != nil { + return nil, err + } + } + + logger.Debugc(ctx.Request().Context(), "AuthorizationResponse presentation_submission decoded", + log.WithState(res.State)) + err = decodeFormValue(&res.State, "state", req.PostForm) if err != nil { return nil, err diff --git a/pkg/restapi/v1/verifier/controller_test.go b/pkg/restapi/v1/verifier/controller_test.go index 5c8f9795c..d21a98250 100644 --- a/pkg/restapi/v1/verifier/controller_test.go +++ b/pkg/restapi/v1/verifier/controller_test.go @@ -466,23 +466,23 @@ func TestController_VerifyPresentation(t *testing.T) { } func TestController_CheckAuthorizationResponse(t *testing.T) { - oidc4VPService := NewMockOIDC4VPService(gomock.NewController(t)) - oidc4VPService.EXPECT().VerifyOIDCVerifiablePresentation(gomock.Any(), oidc4vp.TxID("txid"), gomock.Any()). + svc := NewMockOIDC4VPService(gomock.NewController(t)) + svc.EXPECT().VerifyOIDCVerifiablePresentation(gomock.Any(), oidc4vp.TxID("txid"), gomock.Any()). AnyTimes().Return(nil) t.Run("Success Controller JWT", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: validAud, Iss: signedClaimsJWTResult.VerMethodDID, @@ -497,10 +497,15 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpToken + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -510,36 +515,34 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) + err = c.CheckAuthorizationResponse(ctx) require.NoError(t, err) }) t.Run("Success JWT", func(t *testing.T) { - customScopeClaims := map[string]oidc4vp.Claims{ - "customScope": { - "key1": "value2", + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, }, - } - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - CustomScopeClaims: customScopeClaims, - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + ) vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Iss: signedClaimsJWTResult.VerMethodDID, + Exp: time.Now().Unix() + 1000, VP: &verifiable.Presentation{ Context: []string{ "https://www.w3.org/2018/credentials/v1", @@ -550,42 +553,43 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - Nonce: validNonce, - Aud: validAud, - Iss: signedClaimsJWTResult.VerMethodDID, - Exp: time.Now().Unix() + 1000, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) + + body := "vp_token=" + vpToken + + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + + "&state=txid" + + ctx := createContextApplicationForm([]byte(body)) mockEventSvc := NewMockeventService(gomock.NewController(t)) mockEventSvc.EXPECT().Publish(gomock.Any(), spi.VerifierEventTopic, gomock.Any()).Times(0) c := NewController(&Config{ - OIDCVPService: oidc4VPService, + VDR: signedClaimsJWTResult.VDR, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, - VDR: signedClaimsJWTResult.VDR, DocumentLoader: testutil.DocumentLoader(t), + Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - authorisationResponseParsed, err := c.verifyAuthorizationResponseTokens(context.TODO(), &rawAuthorizationResponse{ - IDToken: signedClaimsJWTResult.JWT, - VPToken: []string{vpToken}, - State: "txid", - }) - + err = c.CheckAuthorizationResponse(ctx) require.NoError(t, err) - require.Equal(t, customScopeClaims, authorisationResponseParsed.CustomScopeClaims) - require.Contains(t, authorisationResponseParsed.VPTokens[0].Presentation.Type, "PresentationSubmission") }) t.Run("Success LDP", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpSigned := testutil.SignedVPWithExistingPrivateKey(t, &verifiable.Presentation{ @@ -611,22 +615,28 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { vpToken, err := vpSigned.MarshalJSON() require.NoError(t, err) + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) + mockEventSvc := NewMockeventService(gomock.NewController(t)) mockEventSvc.EXPECT().Publish(gomock.Any(), spi.VerifierEventTopic, gomock.Any()).Times(0) c := NewController(&Config{ - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, VDR: signedClaimsJWTResult.VDR, DocumentLoader: testutil.DocumentLoader(t), }) - authorisationResponseParsed, err := c.verifyAuthorizationResponseTokens(context.TODO(), &rawAuthorizationResponse{ - IDToken: signedClaimsJWTResult.JWT, - VPToken: []string{string(vpToken)}, - State: "txid", - }) + authorisationResponseParsed, err := c.verifyAuthorizationResponseTokens(context.TODO(), + &rawAuthorizationResponse{ + IDToken: signedClaimsJWTResult.JWT, + VPToken: []string{string(vpToken)}, + PresentationSubmission: string(presentationSubmission), + State: "txid", + }, + ) require.NoError(t, err) @@ -634,19 +644,82 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { require.Contains(t, authorisationResponseParsed.VPTokens[0].Presentation.Type, "PresentationSubmission") }) - t.Run("Presentation submission missed", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: nil}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, + t.Run("Success JWT ID1", func(t *testing.T) { + customScopeClaims := map[string]oidc4vp.Claims{ + "customScope": { + "key1": "value2", + }, + } + + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &idTokenClaimsID1{ + CustomScopeClaims: customScopeClaims, + VPToken: idTokenVPToken{ + PresentationSubmission: map[string]interface{}{}, + }, + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) + + vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, + signedClaimsJWTResult.VerMethodDIDKeyID, + signedClaimsJWTResult.Signer, + &VPTokenClaims{ + VP: &verifiable.Presentation{ + Context: []string{ + "https://www.w3.org/2018/credentials/v1", + "https://identity.foundation/presentation-exchange/submission/v1", + }, + Type: []string{ + "VerifiablePresentation", + "PresentationSubmission", + }, + }, + Nonce: validNonce, + Aud: validAud, + Iss: signedClaimsJWTResult.VerMethodDID, + Exp: time.Now().Unix() + 1000, + }) + + mockEventSvc := NewMockeventService(gomock.NewController(t)) + mockEventSvc.EXPECT().Publish(gomock.Any(), spi.VerifierEventTopic, gomock.Any()).Times(0) + + c := NewController(&Config{ + OIDCVPService: svc, + EventSvc: mockEventSvc, + EventTopic: spi.VerifierEventTopic, + VDR: signedClaimsJWTResult.VDR, + DocumentLoader: testutil.DocumentLoader(t), }) + responseParsed, err := c.verifyAuthorizationResponseTokens(context.Background(), + &rawAuthorizationResponse{ + IDToken: signedClaimsJWTResult.JWT, + VPToken: []string{vpToken}, + State: "txid", + }, + ) + + require.NoError(t, err) + require.Equal(t, customScopeClaims, responseParsed.CustomScopeClaims) + require.Contains(t, responseParsed.VPTokens[0].Presentation.Type, "PresentationSubmission") + }) + + t.Run("Presentation submission missed", func(t *testing.T) { + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) + vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: validAud, Iss: signedClaimsJWTResult.VerMethodDID, @@ -661,7 +734,8 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) body := "vp_token=" + vpToken + "&id_token=" + signedClaimsJWTResult.JWT + @@ -694,7 +768,7 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, DocumentLoader: testutil.DocumentLoader(t), EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, @@ -702,23 +776,75 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { }) err := c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "id_token._vp_token.presentation_submission", err) + requireValidationError(t, resterr.InvalidValue, "presentation_submission", err) }) - t.Run("Nonce different", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, + t.Run("Presentation submission invalid", func(t *testing.T) { + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) + + vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, + signedClaimsJWTResult.VerMethodDIDKeyID, + signedClaimsJWTResult.Signer, + &VPTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Iss: signedClaimsJWTResult.VerMethodDID, + Exp: time.Now().Unix() + 1000, + VP: &verifiable.Presentation{ + Context: []string{ + "https://www.w3.org/2018/credentials/v1", + "https://identity.foundation/presentation-exchange/submission/v1", + }, + Type: []string{ + "VerifiablePresentation", + "PresentationSubmission", + }, + }, + }, + ) + + body := "vp_token=" + vpToken + + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=invalid" + + "&state=txid" + + ctx := createContextApplicationForm([]byte(body)) + + mockEventSvc := NewMockeventService(gomock.NewController(t)) + mockEventSvc.EXPECT().Publish(gomock.Any(), spi.VerifierEventTopic, gomock.Any()).Times(1) + + c := NewController(&Config{ + VDR: signedClaimsJWTResult.VDR, + OIDCVPService: svc, + EventSvc: mockEventSvc, + EventTopic: spi.VerifierEventTopic, + DocumentLoader: testutil.DocumentLoader(t), + Tracer: trace.NewNoopTracerProvider().Tracer(""), }) + err := c.CheckAuthorizationResponse(ctx) + requireValidationError(t, resterr.InvalidValue, "presentation_submission", err) + }) + + t.Run("Nonce different", func(t *testing.T) { + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) + vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: "some_invalid", Aud: validAud, Exp: time.Now().Unix() + 1000, @@ -733,10 +859,15 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpToken + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -746,31 +877,30 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "nonce", err) + err = c.CheckAuthorizationResponse(ctx) + requireValidationError(t, resterr.InvalidValue, "nonce", err) }) t.Run("Aud different", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: "some_invalid", Exp: time.Now().Unix() + 1000, @@ -785,10 +915,15 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpToken + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -798,31 +933,31 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) + err = c.CheckAuthorizationResponse(ctx) requireValidationError(t, resterr.InvalidValue, "aud", err) }) t.Run("ID token expired", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: 0, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: 0, + }, + ) vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: "some_invalid", Iss: signedClaimsJWTResult.VerMethodDID, @@ -837,10 +972,15 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpToken + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -850,30 +990,29 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "id_token.exp", err) + err = c.CheckAuthorizationResponse(ctx) + requireValidationError(t, resterr.InvalidValue, "id_token.exp", err) }) t.Run("ID token invalid signature", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: 0, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: 0, + }, + ) // Signing vpToken using different key. vpTokenSignedJWTResult := testutil.SignedClaimsJWT(t, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: "some_invalid", Exp: time.Now().Unix() + 1000, @@ -888,10 +1027,15 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpTokenSignedJWTResult.JWT + "&id_token=" + vpTokenSignedJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -902,31 +1046,30 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ // Using different key in controller. VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "id_token", err) + err = c.CheckAuthorizationResponse(ctx) + requireValidationError(t, resterr.InvalidValue, "id_token", err) }) t.Run("VP token JWT expired", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: "some_invalid", Iss: signedClaimsJWTResult.VerMethodDID, @@ -941,10 +1084,15 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpToken + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -954,30 +1102,29 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "vp_token.exp", err) + err = c.CheckAuthorizationResponse(ctx) + requireValidationError(t, resterr.InvalidValue, "vp_token.exp", err) }) t.Run("VP token JWT invalid signature", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) // Signing vpToken using different key. vpTokenSignedJWTResult := testutil.SignedClaimsJWT(t, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: validAud, Iss: signedClaimsJWTResult.VerMethodDID, @@ -992,10 +1139,15 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { "PresentationSubmission", }, }, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpTokenSignedJWTResult.JWT + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -1006,40 +1158,44 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ // Using different key in controller. VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "vp_token", err) + err = c.CheckAuthorizationResponse(ctx) + requireValidationError(t, resterr.InvalidValue, "vp_token", err) }) t.Run("VP token JWT parse VP failed", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpToken := testutil.SignedClaimsJWTWithExistingPrivateKey(t, signedClaimsJWTResult.VerMethodDIDKeyID, signedClaimsJWTResult.Signer, - &vpTokenClaims{ + &VPTokenClaims{ Nonce: validNonce, Aud: validAud, Iss: signedClaimsJWTResult.VerMethodDID, Exp: time.Now().Unix() + 1000, VP: &verifiable.Presentation{}, - }) + }, + ) + + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) body := "vp_token=" + vpToken + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -1049,26 +1205,25 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { c := NewController(&Config{ VDR: signedClaimsJWTResult.VDR, - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, DocumentLoader: testutil.DocumentLoader(t), Tracer: trace.NewNoopTracerProvider().Tracer(""), }) - err := c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "vp_token.vp", err) + err = c.CheckAuthorizationResponse(ctx) + requireValidationError(t, resterr.InvalidValue, "vp_token.vp", err) }) t.Run("VP token LDP invalid signature", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpb, err := (&verifiable.Presentation{ Context: []string{ @@ -1094,8 +1249,12 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { vpToken, err := vpSigned.Presentation.MarshalJSON() require.NoError(t, err) + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) + body := "vp_token=" + string(vpToken) + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -1104,7 +1263,7 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { mockEventSvc.EXPECT().Publish(gomock.Any(), spi.VerifierEventTopic, gomock.Any()).Times(1) c := NewController(&Config{ - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, VDR: signedClaimsJWTResult.VDR, @@ -1118,13 +1277,13 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { }) t.Run("VP token LDP challenge (nonce) missed", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpSigned := testutil.SignedVPWithExistingPrivateKey(t, &verifiable.Presentation{ @@ -1150,8 +1309,12 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { vpToken, err := vpSigned.MarshalJSON() require.NoError(t, err) + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) + body := "vp_token=" + string(vpToken) + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -1160,7 +1323,7 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { mockEventSvc.EXPECT().Publish(gomock.Any(), spi.VerifierEventTopic, gomock.Any()).Times(1) c := NewController(&Config{ - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, VDR: signedClaimsJWTResult.VDR, @@ -1169,18 +1332,17 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { }) err = c.CheckAuthorizationResponse(ctx) - requireValidationError(t, resterr.InvalidValue, - "vp_token.challenge", err) + requireValidationError(t, resterr.InvalidValue, "vp_token.challenge", err) }) t.Run("VP token LDP domain (audience) missed", func(t *testing.T) { - signedClaimsJWTResult := testutil.SignedClaimsJWT(t, &IDTokenClaims{ - VPToken: IDTokenVPToken{ - PresentationSubmission: map[string]interface{}{}}, - Nonce: validNonce, - Aud: validAud, - Exp: time.Now().Unix() + 1000, - }) + signedClaimsJWTResult := testutil.SignedClaimsJWT(t, + &IDTokenClaims{ + Nonce: validNonce, + Aud: validAud, + Exp: time.Now().Unix() + 1000, + }, + ) vpSigned := testutil.SignedVPWithExistingPrivateKey(t, &verifiable.Presentation{ @@ -1206,8 +1368,12 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { vpToken, err := vpSigned.MarshalJSON() require.NoError(t, err) + presentationSubmission, err := json.Marshal(map[string]interface{}{}) + require.NoError(t, err) + body := "vp_token=" + string(vpToken) + "&id_token=" + signedClaimsJWTResult.JWT + + "&presentation_submission=" + string(presentationSubmission) + "&state=txid" ctx := createContextApplicationForm([]byte(body)) @@ -1216,7 +1382,7 @@ func TestController_CheckAuthorizationResponse(t *testing.T) { mockEventSvc.EXPECT().Publish(gomock.Any(), spi.VerifierEventTopic, gomock.Any()).Times(1) c := NewController(&Config{ - OIDCVPService: oidc4VPService, + OIDCVPService: svc, EventSvc: mockEventSvc, EventTopic: spi.VerifierEventTopic, VDR: signedClaimsJWTResult.VDR, @@ -2367,12 +2533,17 @@ func TestApplyFieldsFilter(t *testing.T) { }) } -type vpTokenClaims struct { - VP *verifiable.Presentation `json:"vp"` - Nonce string `json:"nonce"` - Aud string `json:"aud"` - Iss string `json:"iss"` - Exp int64 `json:"exp"` +type idTokenClaimsID1 struct { + CustomScopeClaims map[string]oidc4vp.Claims `json:"_scope,omitempty"` + VPToken idTokenVPToken `json:"_vp_token"` + AttestationVP string `json:"_attestation_vp"` + Nonce string `json:"nonce"` + Aud string `json:"aud"` + Exp int64 `json:"exp"` +} + +type idTokenVPToken struct { + PresentationSubmission map[string]interface{} `json:"presentation_submission"` } // nolint:gochecknoglobals diff --git a/pkg/service/oidc4vp/api.go b/pkg/service/oidc4vp/api.go index c038dd808..fae31315d 100644 --- a/pkg/service/oidc4vp/api.go +++ b/pkg/service/oidc4vp/api.go @@ -8,6 +8,7 @@ package oidc4vp import ( "context" + "errors" util "github.com/trustbloc/did-go/doc/util/time" "github.com/trustbloc/vc-go/presexch" @@ -17,6 +18,8 @@ import ( profileapi "github.com/trustbloc/vcs/pkg/profile" ) +var ErrDataNotFound = errors.New("data not found") + type InteractionInfo struct { AuthorizationRequest string TxID TxID @@ -98,3 +101,51 @@ type TxNonceStore txNonceStore type TxClaimsStore txClaimsStore type TxStore txStore + +// RequestObject represents the request object sent to the wallet. It contains the presentation definition +// that specifies what verifiable credentials should be sent back by the wallet. +type RequestObject struct { + JTI string `json:"jti"` + IAT int64 `json:"iat"` + ISS string `json:"iss"` + ResponseType string `json:"response_type"` + ResponseMode string `json:"response_mode"` + Scope string `json:"scope"` + Nonce string `json:"nonce"` + ClientID string `json:"client_id"` + ClientIDScheme string `json:"client_id_scheme"` + RedirectURI string `json:"redirect_uri"` + ResponseURI string `json:"response_uri"` + State string `json:"state"` + Exp int64 `json:"exp"` + // Deprecated: Use client_metadata instead. + Registration RequestObjectRegistration `json:"registration"` + // Deprecated: Use top-level "presentation_definition" instead. + Claims RequestObjectClaims `json:"claims"` + ClientMetadata *ClientMetadata `json:"client_metadata"` + PresentationDefinition *presexch.PresentationDefinition `json:"presentation_definition"` +} + +type RequestObjectRegistration struct { + ClientName string `json:"client_name"` + SubjectSyntaxTypesSupported []string `json:"subject_syntax_types_supported"` + VPFormats *presexch.Format `json:"vp_formats"` + ClientPurpose string `json:"client_purpose"` + LogoURI string `json:"logo_uri"` +} + +type RequestObjectClaims struct { + VPToken VPToken `json:"vp_token"` +} + +type VPToken struct { + PresentationDefinition *presexch.PresentationDefinition `json:"presentation_definition"` +} + +type ClientMetadata struct { + ClientName string `json:"client_name"` + SubjectSyntaxTypesSupported []string `json:"subject_syntax_types_supported"` + VPFormats *presexch.Format `json:"vp_formats"` + ClientPurpose string `json:"client_purpose"` + LogoURI string `json:"logo_uri"` +} diff --git a/pkg/service/oidc4vp/oidc4vp_service.go b/pkg/service/oidc4vp/oidc4vp_service.go index 46e4dfb84..230c30024 100644 --- a/pkg/service/oidc4vp/oidc4vp_service.go +++ b/pkg/service/oidc4vp/oidc4vp_service.go @@ -4,7 +4,7 @@ Copyright SecureKey Technologies Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -//go:generate mockgen -destination oidc4vp_service_mocks_test.go -self_package mocks -package oidc4vp_test -source=oidc4vp_service.go -mock_names transactionManager=MockTransactionManager,events=MockEvents,kmsRegistry=MockKMSRegistry,requestObjectPublicStore=MockRequestObjectPublicStore,profileService=MockProfileService,presentationVerifier=MockPresentationVerifier,trustRegistry=MockTrustRegistry +//go:generate mockgen -destination oidc4vp_service_mocks_test.go -self_package mocks -package oidc4vp_test -source=oidc4vp_service.go -mock_names transactionManager=MockTransactionManager,events=MockEvents,kmsRegistry=MockKMSRegistry,requestObjectStore=MockRequestObjectStore,profileService=MockProfileService,presentationVerifier=MockPresentationVerifier,trustRegistry=MockTrustRegistry package oidc4vp @@ -49,8 +49,11 @@ import ( var logger = log.New("oidc4vp-service") const ( - vpSubmissionProperty = "presentation_submission" - customScopeProperty = "_scope" + vpSubmissionProperty = "presentation_submission" + customScopeProperty = "_scope" + vpTokenIDTokenResponseType = "vp_token id_token" //nolint:gosec + directPostResponseMode = "direct_post" + didClientIDScheme = "did" ) const ( @@ -59,8 +62,6 @@ const ( additionalClaimFieldAwardedDate = "awardedDate" ) -var ErrDataNotFound = errors.New("data not found") - type eventService interface { Publish(ctx context.Context, topic string, messages ...*spi.Event) error } @@ -83,7 +84,7 @@ type transactionManager interface { Get(txID TxID) (*Transaction, error) } -type requestObjectPublicStore interface { +type requestObjectStore interface { Publish(ctx context.Context, requestObject string) (string, error) } @@ -110,63 +111,37 @@ type trustRegistry interface { trustregistry.ValidatePresentation } -type RequestObjectClaims struct { - VPToken VPToken `json:"vp_token"` -} -type VPToken struct { - PresentationDefinition *presexch.PresentationDefinition `json:"presentation_definition"` -} - -// RequestObject represents the request object sent to the wallet. It contains the presentation definition -// that specifies what verifiable credentials should be sent back by the wallet. -type RequestObject struct { - JTI string `json:"jti"` - IAT int64 `json:"iat"` - ISS string `json:"iss"` - ResponseType string `json:"response_type"` - ResponseMode string `json:"response_mode"` - Scope string `json:"scope"` - Nonce string `json:"nonce"` - ClientID string `json:"client_id"` - RedirectURI string `json:"redirect_uri"` - State string `json:"state"` - Exp int64 `json:"exp"` - Registration RequestObjectRegistration `json:"registration"` - Claims RequestObjectClaims `json:"claims"` +type metricsProvider interface { + VerifyOIDCVerifiablePresentationTime(value time.Duration) } type Config struct { - TransactionManager transactionManager - RequestObjectPublicStore requestObjectPublicStore - KMSRegistry kmsRegistry - DocumentLoader ld.DocumentLoader - ProfileService profileService - EventSvc eventService - EventTopic string - PresentationVerifier presentationVerifier - VDR vdrapi.Registry - TrustRegistry trustRegistry - - RedirectURL string - TokenLifetime time.Duration - Metrics metricsProvider -} - -type metricsProvider interface { - VerifyOIDCVerifiablePresentationTime(value time.Duration) + TransactionManager transactionManager + RequestObjectStore requestObjectStore + KMSRegistry kmsRegistry + DocumentLoader ld.DocumentLoader + ProfileService profileService + EventSvc eventService + EventTopic string + PresentationVerifier presentationVerifier + VDR vdrapi.Registry + TrustRegistry trustRegistry + RedirectURL string + TokenLifetime time.Duration + Metrics metricsProvider } type Service struct { - eventSvc eventService - eventTopic string - transactionManager transactionManager - requestObjectPublicStore requestObjectPublicStore - kmsRegistry kmsRegistry - documentLoader ld.DocumentLoader - profileService profileService - presentationVerifier presentationVerifier - vdr vdrapi.Registry - trustRegistry trustRegistry + eventSvc eventService + eventTopic string + transactionManager transactionManager + requestObjectStore requestObjectStore + kmsRegistry kmsRegistry + documentLoader ld.DocumentLoader + profileService profileService + presentationVerifier presentationVerifier + vdr vdrapi.Registry + trustRegistry trustRegistry redirectURL string tokenLifetime time.Duration @@ -174,14 +149,6 @@ type Service struct { metrics metricsProvider } -type RequestObjectRegistration struct { - ClientName string `json:"client_name"` - SubjectSyntaxTypesSupported []string `json:"subject_syntax_types_supported"` - VPFormats *presexch.Format `json:"vp_formats"` - ClientPurpose string `json:"client_purpose"` - LogoURI string `json:"logo_uri"` -} - func NewService(cfg *Config) *Service { metrics := cfg.Metrics @@ -190,19 +157,19 @@ func NewService(cfg *Config) *Service { } return &Service{ - eventSvc: cfg.EventSvc, - eventTopic: cfg.EventTopic, - transactionManager: cfg.TransactionManager, - requestObjectPublicStore: cfg.RequestObjectPublicStore, - kmsRegistry: cfg.KMSRegistry, - documentLoader: cfg.DocumentLoader, - profileService: cfg.ProfileService, - presentationVerifier: cfg.PresentationVerifier, - redirectURL: cfg.RedirectURL, - tokenLifetime: cfg.TokenLifetime, - vdr: cfg.VDR, - trustRegistry: cfg.TrustRegistry, - metrics: metrics, + eventSvc: cfg.EventSvc, + eventTopic: cfg.EventTopic, + transactionManager: cfg.TransactionManager, + requestObjectStore: cfg.RequestObjectStore, + kmsRegistry: cfg.KMSRegistry, + documentLoader: cfg.DocumentLoader, + profileService: cfg.ProfileService, + presentationVerifier: cfg.PresentationVerifier, + redirectURL: cfg.RedirectURL, + tokenLifetime: cfg.TokenLifetime, + vdr: cfg.VDR, + trustRegistry: cfg.TrustRegistry, + metrics: metrics, } } @@ -295,7 +262,7 @@ func (s *Service) InitiateOidcInteraction( logger.Debugc(ctx, "InitiateOidcInteraction request object created") - requestURI, err := s.requestObjectPublicStore.Publish(ctx, token) + requestURI, err := s.requestObjectStore.Publish(ctx, token) if err != nil { e := fmt.Errorf("failed to publish request object: %w", err) @@ -864,17 +831,18 @@ func (s *Service) createRequestObject( tokenLifetime := s.tokenLifetime now := time.Now() return &RequestObject{ - JTI: uuid.New().String(), - IAT: now.Unix(), - ISS: profile.SigningDID.DID, - ResponseType: "id_token", - ResponseMode: "post", - Scope: getScope(customScopes), - Nonce: nonce, - ClientID: profile.SigningDID.DID, - RedirectURI: s.redirectURL, - State: string(tx.ID), - Exp: now.Add(tokenLifetime).Unix(), + JTI: uuid.New().String(), + IAT: now.Unix(), + ISS: profile.SigningDID.DID, + ResponseType: vpTokenIDTokenResponseType, + ResponseMode: directPostResponseMode, + Scope: getScope(customScopes), + Nonce: nonce, + ClientID: profile.SigningDID.DID, + ClientIDScheme: didClientIDScheme, + RedirectURI: s.redirectURL, + State: string(tx.ID), + Exp: now.Add(tokenLifetime).Unix(), Registration: RequestObjectRegistration{ ClientName: profile.Name, SubjectSyntaxTypesSupported: []string{"did:ion"}, @@ -885,6 +853,14 @@ func (s *Service) createRequestObject( Claims: RequestObjectClaims{VPToken: VPToken{ presentationDefinition, }}, + ClientMetadata: &ClientMetadata{ + ClientName: profile.Name, + SubjectSyntaxTypesSupported: []string{"did:web", "did:jwk", "did:key", "did:ion"}, + VPFormats: vpFormats, + ClientPurpose: purpose, + LogoURI: profile.LogoURL, + }, + PresentationDefinition: presentationDefinition, } } diff --git a/pkg/service/oidc4vp/oidc4vp_service_test.go b/pkg/service/oidc4vp/oidc4vp_service_test.go index c65d4f4cc..8b8b8e688 100644 --- a/pkg/service/oidc4vp/oidc4vp_service_test.go +++ b/pkg/service/oidc4vp/oidc4vp_service_test.go @@ -84,20 +84,21 @@ func TestService_InitiateOidcInteraction(t *testing.T) { PresentationDefinition: &presexch.PresentationDefinition{}, CustomScopes: []string{customScope}, }, "nonce1", nil) - requestObjectPublicStore := NewMockRequestObjectPublicStore(gomock.NewController(t)) - requestObjectPublicStore.EXPECT().Publish(gomock.Any(), gomock.Any()). + + requestObjectStore := NewMockRequestObjectStore(gomock.NewController(t)) + requestObjectStore.EXPECT().Publish(gomock.Any(), gomock.Any()). AnyTimes().DoAndReturn(func(ctx context.Context, token string) (string, error) { return "someurl/abc", nil }) s := oidc4vp.NewService(&oidc4vp.Config{ - EventSvc: &mockEvent{}, - EventTopic: spi.VerifierEventTopic, - TransactionManager: txManager, - RequestObjectPublicStore: requestObjectPublicStore, - KMSRegistry: kmsRegistry, - RedirectURL: "test://redirect", - TokenLifetime: time.Second * 100, + EventSvc: &mockEvent{}, + EventTopic: spi.VerifierEventTopic, + TransactionManager: txManager, + RequestObjectStore: requestObjectStore, + KMSRegistry: kmsRegistry, + RedirectURL: "test://redirect", + TokenLifetime: time.Second * 100, }) pubKey, err := keyCreator.Create(kms.ED25519Type) @@ -165,12 +166,12 @@ func TestService_InitiateOidcInteraction(t *testing.T) { Return(nil, "", errors.New("fail")) withError := oidc4vp.NewService(&oidc4vp.Config{ - EventSvc: &mockEvent{}, - EventTopic: spi.VerifierEventTopic, - TransactionManager: txManagerErr, - RequestObjectPublicStore: requestObjectPublicStore, - KMSRegistry: kmsRegistry, - RedirectURL: "test://redirect", + EventSvc: &mockEvent{}, + EventTopic: spi.VerifierEventTopic, + TransactionManager: txManagerErr, + RequestObjectStore: requestObjectStore, + KMSRegistry: kmsRegistry, + RedirectURL: "test://redirect", }) info, err := withError.InitiateOidcInteraction( @@ -186,17 +187,17 @@ func TestService_InitiateOidcInteraction(t *testing.T) { }) t.Run("publish request object failed", func(t *testing.T) { - requestObjectPublicStoreErr := NewMockRequestObjectPublicStore(gomock.NewController(t)) - requestObjectPublicStoreErr.EXPECT().Publish(gomock.Any(), gomock.Any()). + requestObjectStoreErr := NewMockRequestObjectStore(gomock.NewController(t)) + requestObjectStoreErr.EXPECT().Publish(gomock.Any(), gomock.Any()). AnyTimes().Return("", errors.New("fail")) withError := oidc4vp.NewService(&oidc4vp.Config{ - EventSvc: &mockEvent{}, - EventTopic: spi.VerifierEventTopic, - TransactionManager: txManager, - RequestObjectPublicStore: requestObjectPublicStoreErr, - KMSRegistry: kmsRegistry, - RedirectURL: "test://redirect", + EventSvc: &mockEvent{}, + EventTopic: spi.VerifierEventTopic, + TransactionManager: txManager, + RequestObjectStore: requestObjectStoreErr, + KMSRegistry: kmsRegistry, + RedirectURL: "test://redirect", }) info, err := withError.InitiateOidcInteraction( @@ -216,12 +217,12 @@ func TestService_InitiateOidcInteraction(t *testing.T) { kmsRegistry.EXPECT().GetKeyManager(gomock.Any()).AnyTimes().Return(nil, errors.New("fail")) withError := oidc4vp.NewService(&oidc4vp.Config{ - EventSvc: &mockEvent{}, - EventTopic: spi.VerifierEventTopic, - TransactionManager: txManager, - RequestObjectPublicStore: requestObjectPublicStore, - KMSRegistry: kmsRegistry, - RedirectURL: "test://redirect", + EventSvc: &mockEvent{}, + EventTopic: spi.VerifierEventTopic, + TransactionManager: txManager, + RequestObjectStore: requestObjectStore, + KMSRegistry: kmsRegistry, + RedirectURL: "test://redirect", }) info, err := withError.InitiateOidcInteraction(