From 0d7ae93fa373b5fb029c5e8382453279ce266266 Mon Sep 17 00:00:00 2001 From: sanderPostma Date: Thu, 3 Oct 2024 13:38:17 +0200 Subject: [PATCH] chore: responseRedirectUri fixes --- .../lib/__tests__/RP.request.spec.ts | 10 ++++++--- .../lib/authorization-request/types.ts | 2 -- .../PresentationExchange.ts | 4 ++-- packages/siop-oid4vp/lib/rp/RP.ts | 21 ++++++++++--------- packages/siop-oid4vp/lib/rp/RPBuilder.ts | 4 ++-- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/siop-oid4vp/lib/__tests__/RP.request.spec.ts b/packages/siop-oid4vp/lib/__tests__/RP.request.spec.ts index 7cc9c87d..c98e84c1 100644 --- a/packages/siop-oid4vp/lib/__tests__/RP.request.spec.ts +++ b/packages/siop-oid4vp/lib/__tests__/RP.request.spec.ts @@ -27,6 +27,7 @@ import { const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello' const EXAMPLE_REFERENCE_URL = 'https://rp.acme.com/siop/jwts' +const EXAMPLE_RESPONSE_REDIRECT_URL = 'https://acme.com/:correlation_id?state=:state' const HEX_KEY = 'f857544a9d1097e242ff0b287a7e6e90f19cf973efe2317f2a4678739664420f' const DID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0' const KID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0#keys-1' @@ -257,12 +258,13 @@ describe('RP should', () => { const expectedJwtRegex = /^eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6ZXRocjoweDAxMDZhMmU5ODViMUUxRGU5QjVkZGI0YUY2ZEM5ZTkyOEY0ZTk5RDAja2V5cy0xIiwidHlwIjoiSldUIn0\.eyJpYXQiO.*$/ - const request = await RP.builder({ requestVersion: SupportedVersion.SIOPv2_ID1 }) + const rp = RP.builder({ requestVersion: SupportedVersion.SIOPv2_ID1 }) .withClientId(WELL_KNOWN_OPENID_FEDERATION, alltargets) .withScope('test', alltargets) .withResponseType(ResponseType.ID_TOKEN, alltargets) .withVerifyJwtCallback(getVerifyJwtCallback(getResolver('ethr'))) .withRedirectUri(EXAMPLE_REDIRECT_URL, alltargets) + .withResponseRedirectUri(EXAMPLE_RESPONSE_REDIRECT_URL) .withRequestBy(PassBy.REFERENCE, EXAMPLE_REFERENCE_URL) .withCreateJwtCallback(internalSignature(HEX_KEY, DID, KID, SigningAlgo.ES256K)) .withClientMetadata( @@ -296,8 +298,7 @@ describe('RP should', () => { ) .withSupportedVersions([SupportedVersion.SIOPv2_D11]) .build() - - .createAuthorizationRequestURI({ + const request = await rp.createAuthorizationRequestURI({ correlationId: '1234', state: 'b32f0087fc9816eb813fd11f', nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', @@ -306,5 +307,8 @@ describe('RP should', () => { expect(request.authorizationRequestPayload).toMatchObject(expectedPayloadWithoutRequest) expect(request.encodedUri).toMatch(expectedUri) expect(request.requestObjectJwt).toMatch(expectedJwtRegex) + + const responseRedirectUri = rp.getResponseRedirectUri({correlation_id: '1234', state: 'b32f0087fc9816eb813fd11f'}) + expect(responseRedirectUri).toBe('https://acme.com/1234?state=b32f0087fc9816eb813fd11f') }) }) diff --git a/packages/siop-oid4vp/lib/authorization-request/types.ts b/packages/siop-oid4vp/lib/authorization-request/types.ts index 2889147b..64956db9 100644 --- a/packages/siop-oid4vp/lib/authorization-request/types.ts +++ b/packages/siop-oid4vp/lib/authorization-request/types.ts @@ -56,13 +56,11 @@ export interface RequestObjectPayloadOpts { interface AuthorizationRequestCommonOpts { // Yes, this includes common payload properties both at the payload level as well as in the requestObject.payload property. That is to support OAuth2 with or without a signed OpenID requestObject - version: SupportedVersion clientMetadata?: ClientMetadataOpts // this maps to 'registration' for older SIOPv2 specs! OPTIONAL. This parameter is used by the RP to provide information about itself to a Self-Issued OP that would normally be provided to an OP during Dynamic RP Registration, as specified in {#rp-registration-parameter}. payload?: AuthorizationRequestPayloadOpts requestObject: RequestObjectOpts uriScheme?: Schema | string // Use a custom scheme for the URI. By default openid:// will be used - responseRedirectUri?: string; } export type AuthorizationRequestOptsVID1 = AuthorizationRequestCommonOpts diff --git a/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts b/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts index f8464dda..8ad2db76 100644 --- a/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts +++ b/packages/siop-oid4vp/lib/authorization-response/PresentationExchange.ts @@ -166,7 +166,7 @@ export class PresentationExchange { wvp.original, opts, ) - if (evaluationResults.errors.length) { + if (evaluationResults.errors?.length) { throw new Error(`message: ${SIOPErrors.COULD_NOT_FIND_VCS_MATCHING_PD}, details: ${JSON.stringify(evaluationResults.errors)}`) } return evaluationResults @@ -379,7 +379,7 @@ export class PresentationExchange { throw new Error(SIOPErrors.NO_PRESENTATION_SUBMISSION) } - if (!evaluationResults.areRequiredCredentialsPresent || evaluationResults.errors.length > 0 || !evaluationResults.value) { + if (!evaluationResults.areRequiredCredentialsPresent || (evaluationResults.errors && evaluationResults.errors.length > 0) || !evaluationResults.value) { throw new Error(`message: ${SIOPErrors.COULD_NOT_FIND_VCS_MATCHING_PD}, details: ${JSON.stringify(evaluationResults.errors)}`) } diff --git a/packages/siop-oid4vp/lib/rp/RP.ts b/packages/siop-oid4vp/lib/rp/RP.ts index 5c5a2e4d..d876c29d 100644 --- a/packages/siop-oid4vp/lib/rp/RP.ts +++ b/packages/siop-oid4vp/lib/rp/RP.ts @@ -105,14 +105,6 @@ export class RP { responseURIType?: ResponseURIType }): Promise { const authorizationRequestOpts = this.newAuthorizationRequestOpts(opts) - if(authorizationRequestOpts.responseRedirectUri !== undefined) { - authorizationRequestOpts.responseRedirectUri = authorizationRequestOpts.responseRedirectUri - .replace(':correlation_id', opts.correlationId) - .replace(':correlationId', opts.correlationId) - if(typeof(opts.state) === 'string') { - authorizationRequestOpts.responseRedirectUri = authorizationRequestOpts.responseRedirectUri.replace(':state', opts.state) - } - } return await URI.fromOpts(authorizationRequestOpts) .then(async (uri: URI) => { @@ -205,6 +197,17 @@ export class RP { return this._verifyResponseOptions } + public getResponseRedirectUri(mappings: Record): string | undefined { + if (this._responseRedirectUri === undefined) { + return undefined + } + + return Object.entries(mappings).reduce( + (uri, [key, value]) => uri.replace(`:${key}`, value), + this._responseRedirectUri + ) + } + private newAuthorizationRequestOpts(opts: { correlationId: string nonce: string | RequestPropertyWithTargets @@ -304,8 +307,6 @@ export class RP { newOpts.requestObject.payload.claims = { ...newOpts.requestObject.payload.claims, ...claimsWithTarget.propertyValue } } } - - newOpts.responseRedirectUri = this._responseRedirectUri return newOpts } diff --git a/packages/siop-oid4vp/lib/rp/RPBuilder.ts b/packages/siop-oid4vp/lib/rp/RPBuilder.ts index 73e5eb51..fbbdec63 100644 --- a/packages/siop-oid4vp/lib/rp/RPBuilder.ts +++ b/packages/siop-oid4vp/lib/rp/RPBuilder.ts @@ -134,8 +134,8 @@ export class RPBuilder { return this } - withResponseRedirectUri(redirectUri: string, targets?: PropertyTargets): RPBuilder { - this._responseRedirectUri = assignIfAuth({ propertyValue: redirectUri, targets }, false) + withResponseRedirectUri(responseRedirectUri: string): RPBuilder { + this._responseRedirectUri = responseRedirectUri return this }