Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/SPRIND-84 #255

Merged
merged 42 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
31c8608
feat: Implemented OIDF client SDK plugin
zoemaas Oct 17, 2024
b0a6a2f
test: Added verify() and registerCryptoServiceCallback() tests
zoemaas Oct 17, 2024
9088a89
test: Added trust chain build test
zoemaas Oct 18, 2024
30f0e9b
test: Added second trust chain build test
zoemaas Oct 18, 2024
eba4fb4
refactor: Removed the registerCryptoServiceCallback function
zoemaas Oct 18, 2024
d6ce7da
refactor: Removed verifyJwt and register
zoemaas Oct 21, 2024
547d771
chore: Added sign and verify JWT functions
zoemaas Oct 22, 2024
56ce96f
fix: Fixed broken tests
zoemaas Oct 22, 2024
6fe01f4
fix: Implemented temporary cryptoServiceCallback verify function
zoemaas Oct 22, 2024
485b689
fix: Fixed typos in the comments
zoemaas Oct 22, 2024
230dcb5
refactor: Moved the callback to tests
zoemaas Oct 23, 2024
a87ef75
refactor: Improved the readability of comments
zoemaas Oct 24, 2024
689d19d
feature: added Federation Operator credential role for parties
Brummos Oct 29, 2024
45d1ea7
chore: test fix
Brummos Oct 29, 2024
febb187
chore: formatting
Brummos Oct 29, 2024
25695ae
Merge branch 'develop' into feature/SPRIND-84
Brummos Oct 29, 2024
a4f8cc1
refactor: Updated dependencies with the remote version
zoemaas Oct 29, 2024
440405b
refactor: Upgraded pnpm to version 9
zoemaas Oct 29, 2024
3396473
chore: fix build issues
Brummos Oct 29, 2024
19881bc
Merge remote-tracking branch 'origin/feature/SPRIND-84' into feature/…
zoemaas Oct 29, 2024
705edad
fix: Fixed broken test cases
zoemaas Oct 29, 2024
54a716e
chore: added new credential role to migration files
Brummos Oct 29, 2024
51fe2bd
Merge branch 'feature/SPRIND-84' into feature/SPRIND-92
Brummos Oct 30, 2024
ddec5a1
refactor: Added default crypto callback
zoemaas Oct 30, 2024
92ecf6c
chore: integrate oidf-client into oid4vci-holder
Brummos Oct 30, 2024
f95af05
fix: Fixed the non-null expectation of the tests
zoemaas Oct 31, 2024
d41109c
chore: addressing PR comments
Brummos Oct 31, 2024
b2f6ed9
chore: test fixes
Brummos Oct 31, 2024
681242b
refactor: Improved error handling
zoemaas Oct 31, 2024
3bde6b8
chore: fix get trust result
Brummos Nov 1, 2024
e07a610
chore: combined 2 guards for oidf
Brummos Nov 1, 2024
39e7dbe
chore: do not expose get federation trust function to outside of plugin
Brummos Nov 1, 2024
4f892aa
refactor: updated openid-federation dependencies to latest
zoemaas Nov 4, 2024
160dc0e
Merge pull request #259 from Sphereon-Opensource/feature/SPRIND-92
BtencateSphereon Nov 4, 2024
78239ff
Merge remote-tracking branch 'origin/develop' into feature/SPRIND-84
sanderPostma Nov 4, 2024
532edca
chore: skip tests
zoemaas Nov 4, 2024
f6ea2e4
Merge remote-tracking branch 'origin/feature/SPRIND-84' into feature/…
zoemaas Nov 4, 2024
3614645
chore: fixed nockSetup for unit tests
sanderPostma Nov 4, 2024
9347f4e
Merge branch 'feature/SPRIND-84' of https://github.com/Sphereon-Opens…
sanderPostma Nov 4, 2024
4df2666
chore: fixed nockSetup for unit tests
sanderPostma Nov 4, 2024
a774a6e
chore: return trusted anchors instead of booleans so we can determine…
Brummos Nov 4, 2024
3c9ab66
Merge branch 'feature/SPRIND-84' of https://github.com/Sphereon-Opens…
Brummos Nov 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ test/*.js
/packages/pd-manager/plugin.schema.json
/packages/event-logger/plugin.schema.json
/packages/credential-validation/plugin.schema.json
/packages/oidf-client/plugin.schema.json

**/.env.energyshr
**/.env.local
Expand Down
63 changes: 59 additions & 4 deletions packages/data-store/src/__tests__/contact.store.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { DataSources } from '@sphereon/ssi-sdk.agent-config'
import { DataSource } from 'typeorm'
import { DataStoreContactEntities, DataStoreMigrations, IdentityOrigin, MetadataItem, MetadataTypes, PartyOrigin } from '../index'
import {
ConnectionType,
DataStoreContactEntities,
DataStoreMigrations,
IdentityOrigin,
MetadataItem,
MetadataTypes,
PartyOrigin
} from '../index'
import { ContactStore } from '../contact/ContactStore'
import {
CorrelationIdentifierType,
Expand Down Expand Up @@ -367,6 +375,27 @@ describe('Contact store tests', (): void => {
correlationId: 'example_did3',
},
},
{
alias: 'test_alias4',
origin: IdentityOrigin.EXTERNAL,
roles: [CredentialRole.FEDERATION_TRUST_ANCHOR],
connection: {
type: ConnectionType.OPENID_CONNECT,
config: {
clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01',
clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0',
scopes: ['auth'],
issuer: 'https://example.com/app-test',
redirectUrl: 'app:/callback',
dangerouslyAllowInsecureHttpRequests: true,
clientAuthMethod: <const>'post',
},
},
identifier: {
type: CorrelationIdentifierType.URL,
correlationId: 'example_url4',
},
},
],
electronicAddresses: [
{
Expand All @@ -391,7 +420,7 @@ describe('Contact store tests', (): void => {
}
const result: Array<Party> = await contactStore.getParties(args)

expect(result[0].identities.length).toEqual(3)
expect(result[0].identities.length).toEqual(4)
expect(result[0].electronicAddresses.length).toEqual(1)
})

Expand Down Expand Up @@ -1208,15 +1237,41 @@ describe('Contact store tests', (): void => {
correlationId: 'example_did3',
},
},
{
alias: 'test_alias4',
origin: IdentityOrigin.EXTERNAL,
roles: [CredentialRole.FEDERATION_TRUST_ANCHOR],
connection: {
type: ConnectionType.OPENID_CONNECT,
config: {
clientId: '138d7bf8-c930-4c6e-b928-97d3a4928b01',
clientSecret: '03b3955f-d020-4f2a-8a27-4e452d4e27a0',
scopes: ['auth'],
issuer: 'https://example.com/app-test',
redirectUrl: 'app:/callback',
dangerouslyAllowInsecureHttpRequests: true,
clientAuthMethod: <const>'post',
},
},
identifier: {
type: CorrelationIdentifierType.URL,
correlationId: 'example_url4',
},
},
],
}

const savedParty: Party = await contactStore.addParty(party)
const result: Party = await contactStore.getParty({ partyId: savedParty.id })

expect(result.roles).toBeDefined()
expect(result.roles.length).toEqual(3)
expect(result.roles).toEqual([CredentialRole.VERIFIER, CredentialRole.ISSUER, CredentialRole.HOLDER])
expect(result.roles.length).toEqual(4)
expect(result.roles).toEqual([
CredentialRole.VERIFIER,
CredentialRole.ISSUER,
CredentialRole.HOLDER,
CredentialRole.FEDERATION_TRUST_ANCHOR
])
})

it('should add relationship', async (): Promise<void> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class CreateDigitalCredential1708525189001 implements MigrationInterface
await queryRunner.query(`CREATE TYPE "digital_document_type" AS ENUM('VC', 'VP', 'C', 'P')`)
await queryRunner.query(`CREATE TYPE "digital_regulation_type" AS ENUM('PID', 'QEAA', 'EAA', 'NON_REGULATED')`)
await queryRunner.query(`CREATE TYPE "digital_credential_document_format" AS ENUM('JSON_LD', 'JWT', 'SD_JWT', 'MSO_MDOC')`)
await queryRunner.query(`CREATE TYPE "digital_credential_credential_role" AS ENUM('ISSUER', 'VERIFIER', 'HOLDER')`)
await queryRunner.query(`CREATE TYPE "digital_credential_credential_role" AS ENUM('ISSUER', 'VERIFIER', 'HOLDER', 'FEDERATION_TRUST_ANCHOR')`)
await queryRunner.query(`CREATE TYPE "digital_credential_correlation_type" AS ENUM('DID', 'KID', 'URL', 'X509_SAN')`)
await queryRunner.query(`CREATE TYPE "digital_credential_state_type" AS ENUM('REVOKED', 'VERIFIED', 'EXPIRED')`)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class CreateDigitalCredential1708525189002 implements MigrationInterface
"document_type" varchar CHECK( "document_type" IN ('VC', 'VP', 'C', 'P') ) NOT NULL,
"regulation_type" varchar CHECK( "regulation_type" IN ('PID', 'QEAA', 'EAA', 'NON_REGULATED') ) NOT NULL DEFAULT 'NON_REGULATED',
"document_format" varchar CHECK( "document_format" IN ('JSON_LD', 'JWT', 'SD_JWT', 'MSO_MDOC') ) NOT NULL,
"credential_role" varchar CHECK( "credential_role" IN ('ISSUER', 'VERIFIER', 'HOLDER') ) NOT NULL,
"credential_role" varchar CHECK( "credential_role" IN ('ISSUER', 'VERIFIER', 'HOLDER', 'FEDERATION_TRUST_ANCHOR') ) NOT NULL,
"raw_document" text NOT NULL,
"uniform_document" text NOT NULL,
"credential_id" text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export enum CredentialRole {
ISSUER = 'ISSUER',
VERIFIER = 'VERIFIER',
HOLDER = 'HOLDER',
FEDERATION_TRUST_ANCHOR = 'FEDERATION_TRUST_ANCHOR'
}

export enum CredentialStateType {
Expand Down
1 change: 1 addition & 0 deletions packages/oid4vci-holder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@sphereon/ssi-sdk.data-store": "workspace:*",
"@sphereon/ssi-sdk.issuance-branding": "workspace:*",
"@sphereon/ssi-sdk.mdl-mdoc": "workspace:*",
"@sphereon/ssi-sdk.oidf-client": "workspace:*",
"@sphereon/ssi-sdk.sd-jwt": "workspace:*",
"@sphereon/ssi-sdk.xstate-machine-persistence": "workspace:*",
"@sphereon/ssi-types": "workspace:*",
Expand Down
65 changes: 51 additions & 14 deletions packages/oid4vci-holder/src/agent/OID4VCIHolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import {
GetCredentialsArgs,
GetIssuerMetadataArgs,
IOID4VCIHolder,
GetFederationTrustArgs,
IssuanceOpts,
MappedCredentialToAccept,
OID4VCIHolderEvent,
Expand All @@ -101,7 +102,7 @@ import {
StoreCredentialsArgs,
VerificationResult,
VerifyEBSICredentialIssuerArgs,
VerifyEBSICredentialIssuerResult,
VerifyEBSICredentialIssuerResult
} from '../types/IOID4VCIHolder'
import {
getBasicIssuerLocaleBranding,
Expand Down Expand Up @@ -254,8 +255,8 @@ export class OID4VCIHolder implements IAgentPlugin {
didMethodPreferences,
jwtCryptographicSuitePreferences,
defaultAuthorizationRequestOptions,
hasher,
} = options ?? {}
hasher
} = { ...options }

this.hasher = hasher
if (vcFormatPreferences !== undefined && vcFormatPreferences.length > 0) {
Expand Down Expand Up @@ -319,6 +320,7 @@ export class OID4VCIHolder implements IAgentPlugin {
storeCredentialBranding: (args: StoreCredentialBrandingArgs) => this.oid4vciHolderStoreCredentialBranding(args, context),
storeCredentials: (args: StoreCredentialsArgs) => this.oid4vciHolderStoreCredentials(args, context),
sendNotification: (args: SendNotificationArgs) => this.oid4vciHolderSendNotification(args, context),
getFederationTrust: (args: GetFederationTrustArgs) => this.getFederationTrust(args, context)
}

const oid4vciMachineInstanceArgs: OID4VCIMachineInstanceOpts = {
Expand Down Expand Up @@ -987,17 +989,6 @@ export class OID4VCIHolder implements IAgentPlugin {
}
}

private idFromW3cCredentialSubject(wrappedIssuerVC: WrappedW3CVerifiableCredential): string | undefined {
if (Array.isArray(wrappedIssuerVC.credential?.credentialSubject)) {
if (wrappedIssuerVC.credential?.credentialSubject.length > 0) {
return wrappedIssuerVC.credential?.credentialSubject[0].id
}
} else {
return wrappedIssuerVC.credential?.credentialSubject?.id
}
return undefined
}

private async oid4vciHolderSendNotification(args: SendNotificationArgs, context: RequiredContext): Promise<void> {
const { serverMetadata, notificationRequest, openID4VCIClientState } = args
const notificationEndpoint = serverMetadata?.credentialIssuerMetadata?.notification_endpoint
Expand All @@ -1016,6 +1007,41 @@ export class OID4VCIHolder implements IAgentPlugin {
logger.log(`Notification to ${notificationEndpoint} has been dispatched`)
}

private async getFederationTrust(args: GetFederationTrustArgs, context: RequiredContext): Promise<Array<string>> {
const { requestData, serverMetadata, trustAnchors } = args

if (trustAnchors.length === 0) {
return Promise.reject(Error('No trust anchors found'))
}

if (!requestData?.uri) {
return Promise.reject(Error('Missing request URI in context'))
}

if (!serverMetadata) {
return Promise.reject(Error('Missing serverMetadata in context'))
}

const url = new URL(requestData?.uri)
const params = new URLSearchParams(url.search)
const openidFederation = params.get('openid_federation')
const entityIdentifier = openidFederation ?? serverMetadata.issuer

const trustedAnchors = []
for (const trustAnchor of trustAnchors) {
const resolveResult = await context.agent.resolveTrustChain({
entityIdentifier,
trustAnchors: [trustAnchor]
})

if (Array.isArray(resolveResult) && resolveResult.length > 0) {
trustedAnchors.push(trustAnchor)
}
}

return trustedAnchors
}

private async oid4vciHolderGetIssuerMetadata(args: GetIssuerMetadataArgs, context: RequiredContext): Promise<EndpointMetadataResult> {
const { issuer, errorOnNotFound = true } = args
return MetadataClient.retrieveAllMetadata(issuer, { errorOnNotFound })
Expand Down Expand Up @@ -1047,4 +1073,15 @@ export class OID4VCIHolder implements IAgentPlugin {
}
return [CredentialCorrelationType.URL, issuer]
}

private idFromW3cCredentialSubject(wrappedIssuerVC: WrappedW3CVerifiableCredential): string | undefined {
if (Array.isArray(wrappedIssuerVC.credential?.credentialSubject)) {
if (wrappedIssuerVC.credential?.credentialSubject.length > 0) {
return wrappedIssuerVC.credential?.credentialSubject[0].id
}
} else {
return wrappedIssuerVC.credential?.credentialSubject?.id
}
return undefined
}
}
1 change: 0 additions & 1 deletion packages/oid4vci-holder/src/agent/OID4VCIHolderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
} from '@sphereon/ssi-sdk-ext.identifier-resolution'
import { keyTypeFromCryptographicSuite } from '@sphereon/ssi-sdk-ext.key-utils'
import { IBasicCredentialLocaleBranding, IBasicIssuerLocaleBranding } from '@sphereon/ssi-sdk.data-store'

import {
CredentialMapper,
IVerifiableCredential,
Expand Down
5 changes: 4 additions & 1 deletion packages/oid4vci-holder/src/link-handler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
private readonly noStateMachinePersistence: boolean
private readonly authorizationRequestOpts?: AuthorizationRequestOpts
private readonly clientOpts?: AuthorizationServerClientOpts
private readonly trustAnchors?: Array<string>

constructor(
args: Pick<GetMachineArgs, 'stateNavigationListener' | 'authorizationRequestOpts' | 'clientOpts'> & {
args: Pick<GetMachineArgs, 'stateNavigationListener' | 'authorizationRequestOpts' | 'clientOpts' | 'trustAnchors'> & {
priority?: number | DefaultLinkPriorities
protocols?: Array<string | RegExp>
noStateMachinePersistence?: boolean
Expand All @@ -31,6 +32,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
this.context = args.context
this.noStateMachinePersistence = args.noStateMachinePersistence === true
this.stateNavigationListener = args.stateNavigationListener
this.trustAnchors = args.trustAnchors
}

async handle(
Expand All @@ -57,6 +59,7 @@ export class OID4VCIHolderLinkHandler extends LinkHandlerAdapter {
flowType: opts?.flowType,
uri,
},
trustAnchors: this.trustAnchors,
authorizationRequestOpts: { ...this.authorizationRequestOpts, ...opts?.authorizationRequestOpts },
...((clientOpts.clientId || clientOpts.clientAssertionType) && { clientOpts: clientOpts as AuthorizationServerClientOpts }),
stateNavigationListener: this.stateNavigationListener,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"oid4vci_machine_credential_selection_error_title": "Credential selection",
"oid4vci_machine_initiation_error_title": "Initiate OID4VCI provider",
"oid4vci_machine_credential_verification_failed_message": "The credential verification resulted in an error.",
"oid4vci_machine_credential_verification_schema_failed_message": "The credential schema verification resulted in an error."
"oid4vci_machine_credential_verification_schema_failed_message": "The credential schema verification resulted in an error.",
"oid4vci_machine_retrieve_federation_trust_error_title": "Retrieve federation trust"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"oid4vci_machine_retrieve_contact_error_title": "Ophalen contact",
"oid4vci_machine_credential_selection_error_title": "Credential selectie",
"oid4vci_machine_initiation_error_title": "Initiëren OID4VCI provider",
"oid4vci_machine_credential_verification_failed_message": "Verificatie van de credential leidde tot een fout."
"oid4vci_machine_credential_verification_failed_message": "Verificatie van de credential leidde tot een fout.",
"oid4vci_machine_retrieve_federation_trust_error_title": "Ophalen federatievertrouwen"
}
Loading