UNPKG

@sphereon/did-auth-siop

Version:

Self Issued OpenID V2 (SIOPv2) and OpenID 4 Verifiable Presentations (OID4VP)

290 lines (268 loc) 11.5 kB
import { SigningAlgo } from '@sphereon/oid4vc-common' import { IProofType } from '@sphereon/ssi-types' import nock from 'nock' import { AuthorizationResponseOpts, CreateAuthorizationRequestOpts, OP, PassBy, ResponseIss, ResponseMode, ResponseType, RP, Scope, SubjectIdentifierType, SubjectType, SupportedVersion, VerifyAuthorizationRequestOpts, } from '..' import { getCreateJwtCallback, getVerifyJwtCallback, internalSignature } from './DidJwtTestUtils' import { getResolver } from './ResolverTestUtils' import { mockedGetEnterpriseAuthToken, WELL_KNOWN_OPENID_FEDERATION } from './TestUtils' import { UNIT_TEST_TIMEOUT, VERIFIER_LOGO_FOR_CLIENT, VERIFIER_NAME_FOR_CLIENT, VERIFIER_NAME_FOR_CLIENT_NL, VERIFIERZ_PURPOSE_TO_VERIFY, VERIFIERZ_PURPOSE_TO_VERIFY_NL, } from './data/mockedData' const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello' const EXAMPLE_REFERENCE_URL = 'https://rp.acme.com/siop/jwts' const HEX_KEY = 'f857544a9d1097e242ff0b287a7e6e90f19cf973efe2317f2a4678739664420f' const DID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0' const KID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0#controller' describe('OP OPBuilder should', () => { /*it('throw Error when no arguments are passed', async () => { expect.assertions(1); await expect(() => new OPBuilder().build()).toThrowError(Error); });*/ it('build an OP when all arguments are set', async () => { expect.assertions(1) expect( OP.builder() .withIssuer(ResponseIss.SELF_ISSUED_V2) .withResponseMode(ResponseMode.POST) .withRegistration({ passBy: PassBy.REFERENCE, reference_uri: 'https://registration.here', logo_uri: VERIFIER_LOGO_FOR_CLIENT, clientName: VERIFIER_NAME_FOR_CLIENT, 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100332', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, }) .withCreateJwtCallback(internalSignature('myprivatekey', 'did:example:123', 'did:example:123#key', SigningAlgo.ES256K)) .withVerifyJwtCallback(getVerifyJwtCallback(getResolver('ethr'), { checkLinkedDomain: 'never' })) .withExpiresIn(1000) .withSupportedVersions([SupportedVersion.SIOPv2_ID1]) .build(), ).toBeInstanceOf(OP) }) }) describe('OP should', () => { const responseOpts: AuthorizationResponseOpts = { responseURI: EXAMPLE_REDIRECT_URL, responseURIType: 'redirect_uri', createJwtCallback: getCreateJwtCallback({ hexPrivateKey: HEX_KEY, did: DID, kid: KID, alg: SigningAlgo.ES256K, }), jwtIssuer: { method: 'did', didUrl: KID, alg: SigningAlgo.ES256K }, registration: { authorizationEndpoint: 'www.myauthorizationendpoint.com', responseTypesSupported: [ResponseType.ID_TOKEN], subject_syntax_types_supported: ['did:web'], vpFormats: { ldp_vc: { proof_type: [IProofType.EcdsaSecp256k1Signature2019, IProofType.EcdsaSecp256k1Signature2019], }, }, logo_uri: VERIFIER_LOGO_FOR_CLIENT, clientName: VERIFIER_NAME_FOR_CLIENT, 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100333', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, //TODO: fill it up with actual value issuer: ResponseIss.SELF_ISSUED_V2, passBy: PassBy.VALUE, }, responseMode: ResponseMode.POST, expiresIn: 2000, } const resolver = getResolver('ethr') const verifyOpts: VerifyAuthorizationRequestOpts = { verifyJwtCallback: getVerifyJwtCallback(resolver), verification: {}, correlationId: '1234', supportedVersions: [SupportedVersion.SIOPv2_ID1], nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', } /*it('throw Error when build from request opts without enough params', async () => { expect.assertions(1); await expect(() => OP.fromOpts({} as never, {} as never)).toThrowError(Error); });*/ it('return an OP when all request arguments are set', async () => { expect.assertions(1) expect(OP.fromOpts(responseOpts, verifyOpts)).toBeInstanceOf(OP) }) it( 'succeed from request opts when all params are set', async () => { const mockEntity = await mockedGetEnterpriseAuthToken('ACME Corp') const requestOpts: CreateAuthorizationRequestOpts = { version: SupportedVersion.SIOPv2_ID1, requestObject: { jwtIssuer: { method: 'did', didUrl: `${mockEntity.did}#controller`, alg: SigningAlgo.ES256K, options: { kid: '1234', }, }, passBy: PassBy.REFERENCE, reference_uri: EXAMPLE_REFERENCE_URL, createJwtCallback: getCreateJwtCallback({ hexPrivateKey: mockEntity.hexPrivateKey, did: mockEntity.did, kid: `${mockEntity.did}#controller`, alg: SigningAlgo.ES256K, }), payload: { redirect_uri: EXAMPLE_REDIRECT_URL, client_id: WELL_KNOWN_OPENID_FEDERATION, scope: 'test', response_type: 'id_token', }, }, clientMetadata: { client_id: WELL_KNOWN_OPENID_FEDERATION, idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], subject_syntax_types_supported: ['did:ethr', SubjectIdentifierType.DID], requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], responseTypesSupported: [ResponseType.ID_TOKEN], scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subjectTypesSupported: [SubjectType.PAIRWISE], vpFormatsSupported: { jwt_vc: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, jwt_vp: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, jwt: { alg: [SigningAlgo.EDDSA, SigningAlgo.ES256K, SigningAlgo.ES256] }, }, passBy: PassBy.VALUE, logo_uri: VERIFIER_LOGO_FOR_CLIENT, clientName: VERIFIER_NAME_FOR_CLIENT, 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100334', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, }, } const requestURI = await RP.fromRequestOpts(requestOpts).createAuthorizationRequestURI({ correlationId: '1234', nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', state: 'b32f0087fc9816eb813fd11f', jwtIssuer: { method: 'did', didUrl: `${mockEntity.did}#controller`, alg: SigningAlgo.ES256K, options: { kid: '1234' } }, }) nock('https://rp.acme.com').get('/siop/jwts').reply(200, requestURI.requestObjectJwt) try { const verifiedRequest = await OP.fromOpts(responseOpts, verifyOpts).verifyAuthorizationRequest(requestURI.encodedUri) // console.log(JSON.stringify(verifiedRequest)); expect(verifiedRequest.issuer).toMatch(mockEntity.did) expect(verifiedRequest.jwt).toBeDefined() } catch (e) { if (e.message.includes('Service Unavailable')) { console.warn('Temporarily skipped due to Service Unavailable') } else { throw e } } }, UNIT_TEST_TIMEOUT, ) it('succeed from builder when all params are set', async () => { try { const rpMockEntity = await mockedGetEnterpriseAuthToken('ACME RP') const opMockEntity = await mockedGetEnterpriseAuthToken('ACME OP') const requestURI = await RP.builder({ requestVersion: SupportedVersion.SIOPv2_ID1 }) .withClientId(WELL_KNOWN_OPENID_FEDERATION) .withScope('test') .withResponseType(ResponseType.ID_TOKEN) .withAuthorizationEndpoint('www.myauthorizationendpoint.com') .withRedirectUri(EXAMPLE_REFERENCE_URL) .withVerifyJwtCallback(getVerifyJwtCallback(resolver)) .withRequestBy(PassBy.VALUE) .withCreateJwtCallback( getCreateJwtCallback({ hexPrivateKey: rpMockEntity.hexPrivateKey, did: rpMockEntity.did, kid: `${rpMockEntity.did}#controller`, alg: SigningAlgo.ES256K, }), ) .withClientMetadata({ client_id: WELL_KNOWN_OPENID_FEDERATION, idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA], requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], responseTypesSupported: [ResponseType.ID_TOKEN], vpFormatsSupported: { jwt_vc: { alg: [SigningAlgo.EDDSA] } }, scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subjectTypesSupported: [SubjectType.PAIRWISE], subject_syntax_types_supported: ['did', 'did:ethr'], passBy: PassBy.VALUE, logo_uri: VERIFIER_LOGO_FOR_CLIENT, clientName: VERIFIER_NAME_FOR_CLIENT, 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100335', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, }) .build() .createAuthorizationRequestURI({ correlationId: '1234', nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg', state: 'b32f0087fc9816eb813fd11f', jwtIssuer: { method: 'did', didUrl: `${rpMockEntity.did}#controller`, alg: SigningAlgo.ES256K }, }) const verifiedRequest = await OP.builder() .withSupportedVersions([SupportedVersion.SIOPv2_ID1]) .withExpiresIn(1000) .withIssuer(ResponseIss.SELF_ISSUED_V2) .withVerifyJwtCallback(getVerifyJwtCallback(resolver, { checkLinkedDomain: 'never' })) .withCreateJwtCallback( getCreateJwtCallback({ hexPrivateKey: opMockEntity.hexPrivateKey, did: opMockEntity.did, kid: `${opMockEntity.did}#controller`, alg: SigningAlgo.ES256K, }), ) .withRegistration({ idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA], requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256], responseTypesSupported: [ResponseType.ID_TOKEN], vpFormats: { ldp_vc: { proof_type: [IProofType.EcdsaSecp256k1Signature2019, IProofType.EcdsaSecp256k1Signature2019] } }, scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID], subjectTypesSupported: [SubjectType.PAIRWISE], subject_syntax_types_supported: ['did', 'did:ethr'], passBy: PassBy.VALUE, logo_uri: VERIFIER_LOGO_FOR_CLIENT, clientName: VERIFIER_NAME_FOR_CLIENT, 'clientName#nl-NL': VERIFIER_NAME_FOR_CLIENT_NL + '2022100336', clientPurpose: VERIFIERZ_PURPOSE_TO_VERIFY, 'clientPurpose#nl-NL': VERIFIERZ_PURPOSE_TO_VERIFY_NL, }) .build() .verifyAuthorizationRequest(requestURI.encodedUri) // console.log(JSON.stringify(verifiedRequest)); expect(verifiedRequest.issuer).toMatch(rpMockEntity.did) expect(verifiedRequest.jwt).toBeDefined() } catch (e) { if (e.message.includes('Service Unavailable')) { console.warn('Temporarily skipped due to Service Unavailable') } else { throw e } } }) })