From c48d99a7b2c1fcb6c986fbd42eec51bf85c61607 Mon Sep 17 00:00:00 2001 From: mishasizov-SK <109598497+mishasizov-SK@users.noreply.github.com> Date: Wed, 14 Feb 2024 15:57:18 +0200 Subject: [PATCH] feat(sdk): update Credential Issuer Configuration to ID1 (#724) feat: update Credential Issuer Configuration to ID1 Signed-off-by: Mykhailo Sizov --- .github/workflows/build.yml | 298 +++-- Makefile | 15 + .../display/testdata/issuer_metadata.json | 173 +-- .../openid4ci/credentialconfigurations.go | 58 + .../openid4ci/issuermetadata.go | 8 +- .../openid4ci/issuermetadata_test.go | 22 +- .../openid4ci/supportedcredential.go | 58 - .../testdata/sample_issuer_metadata.json | 205 ++-- .../walletinitiatedinteraction_test.go | 50 +- images/vc-rest/Dockerfile | 33 + pkg/credentialschema/credentialdisplay.go | 56 +- pkg/credentialschema/credentialschema.go | 4 +- pkg/credentialschema/credentialschema_test.go | 6 +- .../testdata/bank_issuer_metadata.json | 173 +-- .../testdata/issuer_metadata.json | 191 +-- ...ssuer_metadata_without_claims_display.json | 59 +- pkg/internal/issuermetadata/issuermetadata.go | 14 +- .../issuermetadata/issuermetadata_test.go | 18 +- .../testdata/sample_issuer_metadata.json | 171 +-- .../testdata/sample_issuer_metadata.jwt | 4 +- .../sample_issuer_metadata_with_order.jwt | 4 +- .../sample_jwt_without_issuer_metadata.jwt | 4 +- pkg/models/issuer/metadata.go | 169 ++- .../issuerinitiatedinteraction_test.go | 10 +- .../sample_signed_issuer_metadata.jwt | 4 +- pkg/openid4ci/walletinitiatedinteraction.go | 13 +- scripts/build_vcs.sh | 26 + test/integration/fixtures/.env | 2 +- .../fixtures/profile/profiles.json | 1074 +++++++++-------- 29 files changed, 1587 insertions(+), 1335 deletions(-) create mode 100644 cmd/wallet-sdk-gomobile/openid4ci/credentialconfigurations.go delete mode 100644 cmd/wallet-sdk-gomobile/openid4ci/supportedcredential.go create mode 100644 images/vc-rest/Dockerfile create mode 100755 scripts/build_vcs.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8b7cd7c7..26c6db4d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,9 +11,7 @@ env: on: push: - branches: [ main ] pull_request: - branches: [ main ] jobs: SemanticPullRequest: @@ -132,151 +130,151 @@ jobs: name: mock-trust-registry path: /tmp/mock-trust-registry.tar - iOSFlutterIntegrationTest: - runs-on: macos-12 - needs: [ BuildMockLoginConsentServer, BuilMockTrustRegistryServer ] - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: ${{ env.GO_VERSION }} - - name: Generate and copy iOS Binding - run: | - echo $PATH - echo ${{ github.workspace }} - echo ${GOPATH} - echo ${GOROOT} - export PATH=$PATH:$GOPATH/bin - echo $PATH - go install golang.org/x/mobile/cmd/gomobile@latest - gomobile init - NEW_VERSION=testVer GIT_REV=testRev BUILD_TIME=testTime make generate-ios-bindings copy-ios-bindings - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOPATH: /Users/runner/work/wallet-sdk/go - - name: Install and start docker - run: | - echo '127.0.0.1 file-server.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 did-resolver.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 vc-rest-echo.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 api-gateway.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 cognito-mock.trustbloc.local' | sudo tee -a /etc/hosts - brew install docker docker-compose - colima start - - name: Download artifacts (Docker images) from previous workflows - uses: actions/download-artifact@v4 - - name: Load mock-login-consent server - run: | - docker load --input mock-login-consent/mock-login-consent.tar - - name: Load mock test registry server - run: | - docker load --input mock-trust-registry/mock-trust-registry.tar - - name: Generate test cli and keys - run: | - make build-integration-cli generate-test-keys - - name: Setup env for integration test - run: | - make start-integration-env-flutter - - name: Setup Flutter SDK - uses: flutter-actions/setup-flutter@v2 - with: - channel: stable - version: 3.10.6 - - name: Install flutter app dependencies - run: make install-flutter-dependencies - - name: Run iOS Simulator - uses: futureware-tech/simulator-action@v3 - with: - model: 'iPhone 14' - - name: Remove AppIcon contents file (Simulator build fails with this file) - run: | - rm -rf demo/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json - rm -rf demo/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json - - name: Run tests on Simulator - run: make integration-test-flutter integration-test-ios - - name: Docker container status output - if: always() - run: | - docker images - docker ps -a - - AndroidFlutterIntegrationTest: - runs-on: macos-12 - needs: [ BuildMockLoginConsentServer, BuilMockTrustRegistryServer ] - steps: - - name: checkout - uses: actions/checkout@v4 - - name: Gradle cache - uses: gradle/gradle-build-action@v3 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: ${{ env.GO_VERSION }} - - name: Generate and copy Android Binding - run: | - echo $PATH - echo ${{ github.workspace }} - echo ${GOPATH} - echo ${GOROOT} - export PATH=$PATH:$GOPATH/bin - echo $PATH - go install golang.org/x/mobile/cmd/gomobile@latest - gomobile init - NEW_VERSION=testVer GIT_REV=testRev BUILD_TIME=testTime make generate-android-bindings copy-android-bindings - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOPATH: /Users/runner/work/wallet-sdk/go - - name: Install and start docker - run: | - echo '127.0.0.1 file-server.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 did-resolver.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 vc-rest-echo.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 api-gateway.trustbloc.local' | sudo tee -a /etc/hosts - echo '127.0.0.1 cognito-mock.trustbloc.local' | sudo tee -a /etc/hosts - brew install docker docker-compose - colima start - - name: Download artifacts (Docker images) from previous workflows - uses: actions/download-artifact@v4 - - name: Load mock-login-consent server - run: | - docker load --input mock-login-consent/mock-login-consent.tar - - name: Load mock test registry server - run: | - docker load --input mock-trust-registry/mock-trust-registry.tar - - name: Generate test cli and keys - run: | - make build-integration-cli generate-test-keys - - name: Setup env for integration test - run: | - make start-integration-env-flutter - - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: '17' - - name: Setup Flutter SDK - uses: flutter-actions/setup-flutter@v2 - with: - channel: stable - version: 3.10.6 - - name: Install flutter app dependencies - run: make install-flutter-dependencies - - name: Build APK in Debug mode - run: | - cd demo/app - flutter build apk --debug - - name: Run flutter and android tests on Emulator - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 32 - arch: x86_64 - force-avd-creation: false - emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none - disable-animations: true - script: adb reverse tcp:8075 tcp:8075 && adb reverse tcp:8072 tcp:8072 && adb reverse tcp:9229 tcp:9229 && make integration-test-flutter integration-test-android - - name: Docker container status output - if: always() - run: | - docker images - docker ps -a +# iOSFlutterIntegrationTest: +# runs-on: macos-12 +# needs: [ BuildMockLoginConsentServer, BuilMockTrustRegistryServer ] +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# - name: Set up Go +# uses: actions/setup-go@v5 +# with: +# go-version: ${{ env.GO_VERSION }} +# - name: Generate and copy iOS Binding +# run: | +# echo $PATH +# echo ${{ github.workspace }} +# echo ${GOPATH} +# echo ${GOROOT} +# export PATH=$PATH:$GOPATH/bin +# echo $PATH +# go install golang.org/x/mobile/cmd/gomobile@latest +# gomobile init +# NEW_VERSION=testVer GIT_REV=testRev BUILD_TIME=testTime make generate-ios-bindings copy-ios-bindings +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# GOPATH: /Users/runner/work/wallet-sdk/go +# - name: Install and start docker +# run: | +# echo '127.0.0.1 file-server.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 did-resolver.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 vc-rest-echo.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 api-gateway.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 cognito-mock.trustbloc.local' | sudo tee -a /etc/hosts +# brew install docker docker-compose +# colima start +# - name: Download artifacts (Docker images) from previous workflows +# uses: actions/download-artifact@v4 +# - name: Load mock-login-consent server +# run: | +# docker load --input mock-login-consent/mock-login-consent.tar +# - name: Load mock test registry server +# run: | +# docker load --input mock-trust-registry/mock-trust-registry.tar +# - name: Generate test cli and keys +# run: | +# make build-integration-cli generate-test-keys +# - name: Setup env for integration test +# run: | +# make start-integration-env-flutter +# - name: Setup Flutter SDK +# uses: flutter-actions/setup-flutter@v2 +# with: +# channel: stable +# version: 3.10.6 +# - name: Install flutter app dependencies +# run: make install-flutter-dependencies +# - name: Run iOS Simulator +# uses: futureware-tech/simulator-action@v3 +# with: +# model: 'iPhone 14' +# - name: Remove AppIcon contents file (Simulator build fails with this file) +# run: | +# rm -rf demo/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +# rm -rf demo/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +# - name: Run tests on Simulator +# run: make integration-test-flutter integration-test-ios +# - name: Docker container status output +# if: always() +# run: | +# docker images +# docker ps -a +# +# AndroidFlutterIntegrationTest: +# runs-on: macos-12 +# needs: [ BuildMockLoginConsentServer, BuilMockTrustRegistryServer ] +# steps: +# - name: checkout +# uses: actions/checkout@v4 +# - name: Gradle cache +# uses: gradle/gradle-build-action@v3 +# - name: Set up Go +# uses: actions/setup-go@v5 +# with: +# go-version: ${{ env.GO_VERSION }} +# - name: Generate and copy Android Binding +# run: | +# echo $PATH +# echo ${{ github.workspace }} +# echo ${GOPATH} +# echo ${GOROOT} +# export PATH=$PATH:$GOPATH/bin +# echo $PATH +# go install golang.org/x/mobile/cmd/gomobile@latest +# gomobile init +# NEW_VERSION=testVer GIT_REV=testRev BUILD_TIME=testTime make generate-android-bindings copy-android-bindings +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# GOPATH: /Users/runner/work/wallet-sdk/go +# - name: Install and start docker +# run: | +# echo '127.0.0.1 file-server.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 did-resolver.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 vc-rest-echo.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 api-gateway.trustbloc.local' | sudo tee -a /etc/hosts +# echo '127.0.0.1 cognito-mock.trustbloc.local' | sudo tee -a /etc/hosts +# brew install docker docker-compose +# colima start +# - name: Download artifacts (Docker images) from previous workflows +# uses: actions/download-artifact@v4 +# - name: Load mock-login-consent server +# run: | +# docker load --input mock-login-consent/mock-login-consent.tar +# - name: Load mock test registry server +# run: | +# docker load --input mock-trust-registry/mock-trust-registry.tar +# - name: Generate test cli and keys +# run: | +# make build-integration-cli generate-test-keys +# - name: Setup env for integration test +# run: | +# make start-integration-env-flutter +# - uses: actions/setup-java@v3 +# with: +# distribution: 'zulu' +# java-version: '17' +# - name: Setup Flutter SDK +# uses: flutter-actions/setup-flutter@v2 +# with: +# channel: stable +# version: 3.10.6 +# - name: Install flutter app dependencies +# run: make install-flutter-dependencies +# - name: Build APK in Debug mode +# run: | +# cd demo/app +# flutter build apk --debug +# - name: Run flutter and android tests on Emulator +# uses: reactivecircus/android-emulator-runner@v2 +# with: +# api-level: 32 +# arch: x86_64 +# force-avd-creation: false +# emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none +# disable-animations: true +# script: adb reverse tcp:8075 tcp:8075 && adb reverse tcp:8072 tcp:8072 && adb reverse tcp:9229 tcp:9229 && make integration-test-flutter integration-test-android +# - name: Docker container status output +# if: always() +# run: | +# docker images +# docker ps -a diff --git a/Makefile b/Makefile index 0de157c0..a50adff1 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ else endif ALPINE_VER ?= 3.18 +GO_ALPINE_VER ?= 3.18 GO_VER ?= 1.21 NEW_VERSION ?= $(shell git describe --tags --always `git rev-list --tags --max-count=1`)-SNAPSHOT-$(shell git rev-parse --short=7 HEAD) @@ -20,12 +21,16 @@ BUILD_TIME ?= $(shell date) # Namespace for the images DOCKER_OUTPUT_NS ?= ghcr.io +VC_REST_IMAGE_NAME ?= trustbloc-cicd/vc-server REPO_IMAGE_NAME ?= trustbloc +GOPROXY ?= https://proxy.golang.org export TERM := xterm-256color ANDROID_EMULATOR_NAME ?= WalletSDKDeviceEmulator +VCS_COMMIT ?= 977063efde1950edc11e14bfe37f370f540c76a7 + .PHONY: all all: checks unit-test integration-test @@ -98,6 +103,16 @@ build-krakend-plugin: clean devopsfaith/krakend-plugin-builder:2.1.3 \ go build -buildmode=plugin -o /opt/workspace/wallet-sdk/test/integration/fixtures/krakend-config/plugins/http-client-no-redirect.so . +.PHONY: vc-rest-docker +vc-rest-docker: + @echo "Building vc rest docker image" + @VCS_COMMIT=$(VCS_COMMIT) scripts/build_vcs.sh + @docker build -f ./images/vc-rest/Dockerfile --no-cache -t $(DOCKER_OUTPUT_NS)/$(VC_REST_IMAGE_NAME):latest \ + --build-arg GO_VER=$(GO_VER) \ + --build-arg GO_PROXY=$(GOPROXY) \ + --build-arg GO_ALPINE_VER=$(GO_ALPINE_VER) \ + --build-arg ALPINE_VER=$(ALPINE_VER) . + .PHONY: integration-test integration-test: mock-login-consent-docker mock-trust-registry-docker generate-test-keys @cd test/integration && go mod tidy && ENABLE_COMPOSITION=true go test -count=1 -v -cover . -p 1 -timeout=10m -race diff --git a/cmd/wallet-sdk-gomobile/display/testdata/issuer_metadata.json b/cmd/wallet-sdk-gomobile/display/testdata/issuer_metadata.json index ec22fb2e..7a9c3ff5 100644 --- a/cmd/wallet-sdk-gomobile/display/testdata/issuer_metadata.json +++ b/cmd/wallet-sdk-gomobile/display/testdata/issuer_metadata.json @@ -1,104 +1,105 @@ { - "credential_issuer":"https://server.example.com", - "authorization_server":"https://server.example.com/oidc/authorize", - "credential_endpoint":"https://server.example.com/oidc/credential", - "display":[ + "credential_issuer": "https://server.example.com", + "authorization_server": "https://server.example.com/oidc/authorize", + "credential_endpoint": "https://server.example.com/oidc/credential", + "display": [ { - "locale":"en-US", - "name":"Example University" + "locale": "en-US", + "name": "Example University" }, { - "name":"サンプル大学", - "locale":"jp-JA" + "name": "サンプル大学", + "locale": "jp-JA" } ], - "credentials_supported":[ - { - "id": "UniversityDegreeCredential", - "format":"jwt_vc_json", - "types":[ - "VerifiableCredential", - "UniversityDegreeCredential" - ], - "credentialSubject":{ - "id":{ - "display":[ - { - "name":"ID", - "locale":"en-US" - } - ], - "value_type":"string", - "order":0 - }, - "given_name":{ - "display":[ - { - "name":"Given Name", - "locale":"en-US" - } - ], - "value_type":"string", - "order":1 - }, - "surname":{ - "display":[ - { - "name":"Surname", - "locale":"en-US" - } - ], - "value_type":"string", - "order":2 - }, - "gpa":{ - "display":[ - { - "name":"GPA", - "locale":"en-US" - } - ], - "value_type":"number" - }, - "sensitive_id":{ - "display":[ - { - "name":"Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex(^(.*).{4}$)" + "credential_configurations_supported": { + "UniversityDegreeCredential_jwt_vc_json_v1": { + "format": "jwt_vc_json", + "credential_definition": { + "credentialSubject": { + "id": { + "display": [ + { + "name": "ID", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 0 + }, + "given_name": { + "display": [ + { + "name": "Given Name", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 1 + }, + "surname": { + "display": [ + { + "name": "Surname", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 2 + }, + "gpa": { + "display": [ + { + "name": "GPA", + "locale": "en-US" + } + ], + "value_type": "number" + }, + "sensitive_id": { + "display": [ + { + "name": "Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex(^(.*).{4}$)" + }, + "really_sensitive_id": { + "display": [ + { + "name": "Really Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex((.*))" + } }, - "really_sensitive_id":{ - "display":[ - { - "name":"Really Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex((.*))" - } + "type": [ + "VerifiableCredential", + "UniversityDegreeCredential" + ] }, - "cryptographic_binding_methods_supported":[ + "cryptographic_binding_methods_supported": [ "ion" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "ECDSASecp256k1DER" ], - "display":[ + "display": [ { - "name":"University Credential", - "locale":"en-US", - "logo":{ - "url":"https://exampleuniversity.com/public/logo.png", - "alt_text":"a square logo of a university" + "name": "University Credential", + "locale": "en-US", + "logo": { + "url": "https://exampleuniversity.com/public/logo.png", + "alt_text": "a square logo of a university" }, - "background_color":"#12107c", - "text_color":"#FFFFFF" + "background_color": "#12107c", + "text_color": "#FFFFFF" } ] } - ] + } } \ No newline at end of file diff --git a/cmd/wallet-sdk-gomobile/openid4ci/credentialconfigurations.go b/cmd/wallet-sdk-gomobile/openid4ci/credentialconfigurations.go new file mode 100644 index 00000000..82f55fd8 --- /dev/null +++ b/cmd/wallet-sdk-gomobile/openid4ci/credentialconfigurations.go @@ -0,0 +1,58 @@ +/* +Copyright Gen Digital Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package openid4ci + +import ( + "github.com/trustbloc/wallet-sdk/cmd/wallet-sdk-gomobile/api" + "github.com/trustbloc/wallet-sdk/pkg/models/issuer" +) + +// CredentialConfigurationsSupported represents the credentials (types and formats) that an issuer can issue. +type CredentialConfigurationsSupported struct { + credentialConfigurations map[issuer.CredentialConfigurationID]*issuer.CredentialConfigurationSupported +} + +// Length returns the number of CredentialConfigurationsSupported contained within this object. +func (s *CredentialConfigurationsSupported) Length() int { + return len(s.credentialConfigurations) +} + +// CredentialConfigurationSupported returns the CredentialConfigurationSupported by given credentialConfigurationID. +// If credentialConfigurationID is unknown, then nil is returned. +func (s *CredentialConfigurationsSupported) CredentialConfigurationSupported( + credentialConfigurationID issuer.CredentialConfigurationID, +) *CredentialConfigurationSupported { + credentialConf, ok := s.credentialConfigurations[credentialConfigurationID] + if !ok { + return nil + } + + return &CredentialConfigurationSupported{credentialConfigurationSupported: credentialConf} +} + +// CredentialConfigurationSupported represents a specific credential (type and format) that an issuer can issue. +type CredentialConfigurationSupported struct { + credentialConfigurationSupported *issuer.CredentialConfigurationSupported +} + +// Format returns this CredentialConfigurationSupported's format. +func (s *CredentialConfigurationSupported) Format() string { + return s.credentialConfigurationSupported.Format +} + +// Types returns this CredentialConfigurationSupported's types. +func (s *CredentialConfigurationSupported) Types() *api.StringArray { + return &api.StringArray{Strings: s.credentialConfigurationSupported.CredentialDefinition.Type} +} + +// LocalizedDisplays returns an object that contains this CredentialConfigurationSupported's +// display data in various locales. +func (s *CredentialConfigurationSupported) LocalizedDisplays() *LocalizedCredentialDisplays { + return &LocalizedCredentialDisplays{ + localizedCredentialDisplays: s.credentialConfigurationSupported.LocalizedCredentialDisplays, + } +} diff --git a/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata.go b/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata.go index a3fd152d..f7fc2368 100644 --- a/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata.go +++ b/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata.go @@ -20,10 +20,10 @@ func (i *IssuerMetadata) CredentialIssuer() string { return i.issuerMetadata.CredentialIssuer } -// SupportedCredentials returns an object that can be used to determine the types of credentials that the issuer -// supports issuance of. -func (i *IssuerMetadata) SupportedCredentials() *SupportedCredentials { - return &SupportedCredentials{supportedCredentials: i.issuerMetadata.CredentialsSupported} +// CredentialConfigurationsSupported returns an object that can be used to determine the types of +// credentials that the issuer supports issuance of. +func (i *IssuerMetadata) CredentialConfigurationsSupported() *CredentialConfigurationsSupported { + return &CredentialConfigurationsSupported{credentialConfigurations: i.issuerMetadata.CredentialConfigurationsSupported} } // LocalizedIssuerDisplays returns an object that contains display information for the issuer in various locales. diff --git a/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata_test.go b/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata_test.go index 056c99f9..3b87579c 100644 --- a/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata_test.go +++ b/cmd/wallet-sdk-gomobile/openid4ci/issuermetadata_test.go @@ -65,24 +65,24 @@ func TestIssuerMetadata(t *testing.T) { require.Nil(t, localizedIssuerDisplays.AtIndex(2)) - supportedCredentials := issuerMetadata.SupportedCredentials() - require.NotNil(t, supportedCredentials) - require.Equal(t, 1, supportedCredentials.Length()) + credentialConfigurationsSupported := issuerMetadata.CredentialConfigurationsSupported() + require.NotNil(t, credentialConfigurationsSupported) + require.Equal(t, 1, credentialConfigurationsSupported.Length()) - supportedCredential := supportedCredentials.AtIndex(0) - require.NotNil(t, supportedCredential) - require.Equal(t, "jwt_vc_json", supportedCredential.Format()) - require.Equal(t, "UniversityDegreeCredential", supportedCredential.ID()) + credentialConfigurationSupported := credentialConfigurationsSupported. + CredentialConfigurationSupported("PermanentResidentCard_jwt_vc_json-ld_v1") + require.NotNil(t, credentialConfigurationSupported) + require.Equal(t, "jwt_vc_json-ld", credentialConfigurationSupported.Format()) - types := supportedCredential.Types() + types := credentialConfigurationSupported.Types() require.NotNil(t, types) require.Equal(t, 2, types.Length()) require.Equal(t, "VerifiableCredential", types.AtIndex(0)) - require.Equal(t, "UniversityDegreeCredential", types.AtIndex(1)) + require.Equal(t, "PermanentResidentCard", types.AtIndex(1)) - require.Nil(t, supportedCredentials.AtIndex(1)) + require.Nil(t, credentialConfigurationsSupported.CredentialConfigurationSupported("")) - localizedDisplays := supportedCredential.LocalizedDisplays() + localizedDisplays := credentialConfigurationSupported.LocalizedDisplays() require.NotNil(t, localizedDisplays) require.Equal(t, 1, localizedDisplays.Length()) diff --git a/cmd/wallet-sdk-gomobile/openid4ci/supportedcredential.go b/cmd/wallet-sdk-gomobile/openid4ci/supportedcredential.go deleted file mode 100644 index 6c3ac532..00000000 --- a/cmd/wallet-sdk-gomobile/openid4ci/supportedcredential.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright Gen Digital Inc. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package openid4ci - -import ( - "github.com/trustbloc/wallet-sdk/cmd/wallet-sdk-gomobile/api" - "github.com/trustbloc/wallet-sdk/pkg/models/issuer" -) - -// SupportedCredentials represents the credentials (types and formats) that an issuer can issue. -type SupportedCredentials struct { - supportedCredentials []issuer.SupportedCredential -} - -// Length returns the number of SupportedCredentials contained within this object. -func (s *SupportedCredentials) Length() int { - return len(s.supportedCredentials) -} - -// AtIndex returns the SupportedCredential at the given index. -// If the index passed in is out of bounds, then nil is returned. -func (s *SupportedCredentials) AtIndex(index int) *SupportedCredential { - maxIndex := len(s.supportedCredentials) - 1 - if index > maxIndex || index < 0 { - return nil - } - - return &SupportedCredential{supportedCredential: &s.supportedCredentials[index]} -} - -// SupportedCredential represents a specific credential (type and format) that an issuer can issue. -type SupportedCredential struct { - supportedCredential *issuer.SupportedCredential -} - -// Format returns this SupportedCredential's format. -func (s *SupportedCredential) Format() string { - return s.supportedCredential.Format -} - -// Types returns this SupportedCredential's types. -func (s *SupportedCredential) Types() *api.StringArray { - return &api.StringArray{Strings: s.supportedCredential.Types} -} - -// ID returns this SupportedCredential's ID. -func (s *SupportedCredential) ID() string { - return s.supportedCredential.ID -} - -// LocalizedDisplays returns an object that contains this SupportedCredential's display data in various locales. -func (s *SupportedCredential) LocalizedDisplays() *LocalizedCredentialDisplays { - return &LocalizedCredentialDisplays{localizedCredentialDisplays: s.supportedCredential.LocalizedCredentialDisplays} -} diff --git a/cmd/wallet-sdk-gomobile/openid4ci/testdata/sample_issuer_metadata.json b/cmd/wallet-sdk-gomobile/openid4ci/testdata/sample_issuer_metadata.json index 26665fcf..35dac5ae 100644 --- a/cmd/wallet-sdk-gomobile/openid4ci/testdata/sample_issuer_metadata.json +++ b/cmd/wallet-sdk-gomobile/openid4ci/testdata/sample_issuer_metadata.json @@ -1,123 +1,102 @@ { - "credential_issuer":"https://server.example.com", - "authorization_server":"https://server.example.com/oidc/authorize", - "credential_endpoint":"https://server.example.com/oidc/credential", - "display":[ + "authorization_endpoint": "https://web.url.com/oidc/authorize", + "credential_ack_endpoint": "https://web.url.com/oidc/acknowledgement", + "credential_configurations_supported": { + "PermanentResidentCard_jwt_vc_json-ld_v1": { + "credential_definition": { + "@context": [ + "http://localhost:4566/doc-store/df7cf304-fdd0-41d3-bbce-01681691c258/v1.0" + ], + "credentialSubject": { + "last_name": { + "mandatory": false, + "value_type": "string", + "display": [ + { + "name": "some-text", + "locale": "en-US" + } + ] + } + }, + "type": [ + "VerifiableCredential", + "PermanentResidentCard" + ] + }, + "display": [ + { + "name": "University Credential", + "locale": "en-US", + "logo": { + "url": "https://exampleuniversity.com/public/degree_logo.png", + "alt_text": "a square logo of an Example University degree" + }, + "background_color": "#12107c", + "text_color": "#FFFFFF" + } + ], + "format": "jwt_vc_json-ld", + "scope": "JSONLD_schema_scope1", + "order": [ + "last_name" + ], + "cryptographic_binding_methods_supported": [ + "web" + ], + "cryptographic_suites_supported": [ + "ECDSAP256DER" + ], + "proof_types": [ + "jwt" + ] + } + }, + "credential_endpoint": "https://web.url.com/oidc/credential", + "credential_issuer": "https://server.example.com", + "credential_response_encryption": { + "alg_values_supported": [ + "RSA1_5", + "RSA-OAEP", + "RSA-OAEP-256" + ], + "enc_values_supported": [ + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512" + ], + "encryption_required": false + }, + "display": [ { - "locale":"en-US", - "name":"Example University", + "locale": "en-US", + "name": "Example University", "url": "https://server.example.com", - "logo":{ - "url":"https://exampleuniversity.com/public/logo.png", - "alt_text":"a square logo of a university" + "logo": { + "url": "https://exampleuniversity.com/public/logo.png", + "alt_text": "a square logo of a university" }, - "background_color":"#12107c", - "text_color":"#FFFFFF" + "background_color": "#12107c", + "text_color": "#FFFFFF" }, { - "name":"サンプル大学", - "locale":"jp-JA", + "name": "サンプル大学", + "locale": "jp-JA", "url": "https://server.example.com", - "background_color":"#12107c", - "text_color":"#FFFFFF" + "background_color": "#12107c", + "text_color": "#FFFFFF" } ], - "credentials_supported":[ - { - "id": "UniversityDegreeCredential", - "format":"jwt_vc_json", - "types":[ - "VerifiableCredential", - "UniversityDegreeCredential" - ], - "credentialSubject":{ - "id":{ - "display":[ - { - "name":"ID", - "locale":"en-US" - } - ], - "value_type":"string", - "order":0 - }, - "given_name":{ - "display":[ - { - "name":"Given Name", - "locale":"en-US" - } - ], - "value_type":"string", - "order":1 - }, - "surname":{ - "display":[ - { - "name":"Surname", - "locale":"en-US" - } - ], - "value_type":"string", - "order":2 - }, - "gpa":{ - "display":[ - { - "name":"GPA", - "locale":"en-US" - } - ], - "value_type":"number" - }, - "sensitive_id":{ - "display":[ - { - "name":"Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex(^(.*).{4}$)" - }, - "really_sensitive_id":{ - "display":[ - { - "name":"Really Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex((.*))" - }, - "chemistry":{ - "display":[ - { - "name":"Chemistry Final Grade", - "locale":"en-US" - } - ], - "value_type":"number" - } - }, - "cryptographic_binding_methods_supported":[ - "ion" - ], - "cryptographic_suites_supported":[ - "ECDSASecp256k1DER" - ], - "display":[ - { - "name":"University Credential", - "locale":"en-US", - "logo":{ - "url":"https://exampleuniversity.com/public/degree_logo.png", - "alt_text":"a square logo of an Example University degree" - }, - "background_color":"#12107c", - "text_color":"#FFFFFF" - } - ] - } + "pre-authorized_grant_anonymous_access_supported": true, + "response_types_supported": [ + "code" + ], + "token_endpoint": "https://web.url.com/oidc/token", + "token_endpoint_auth_methods_supported": [ + "client_secret_basic", + "client_secret_post", + "attest_jwt_client_auth", + "none" ] -} \ No newline at end of file +} + diff --git a/cmd/wallet-sdk-gomobile/openid4ci/walletinitiatedinteraction_test.go b/cmd/wallet-sdk-gomobile/openid4ci/walletinitiatedinteraction_test.go index 70a7cd04..e22de95e 100644 --- a/cmd/wallet-sdk-gomobile/openid4ci/walletinitiatedinteraction_test.go +++ b/cmd/wallet-sdk-gomobile/openid4ci/walletinitiatedinteraction_test.go @@ -33,11 +33,29 @@ func TestWalletInitiatedInteraction_Flow(t *testing.T) { TokenEndpoint: fmt.Sprintf("%s/oidc/token", server.URL), } - issuerServerHandler.issuerMetadata = fmt.Sprintf(`{"credential_endpoint":"%s/credential",`+ - `"credential_issuer":"https://server.example.com",`+ - `"credentials_supported":[{"format":"jwt_vc_json","types":["VerifiableCredential",`+ - `"UniversityDegreeCredential"]},{"format":"ldp_vc","types":["VerifiableCredential",`+ - `"DriversLicenseCredential"]}]}`, server.URL) + issuerServerHandler.issuerMetadata = fmt.Sprintf(`{ + "credential_endpoint": "%s/credential", + "credential_configurations_supported": { + "PermanentResidentCard_jwt_vc_json-ld_v1": { + "credential_definition": { + "type": [ + "VerifiableCredential", + "PermanentResidentCard" + ] + }, + "format": "jwt_vc_json-ld" + }, + "DriversLicenseCredential_ldp_vc_v1": { + "credential_definition": { + "type": [ + "VerifiableCredential", + "DriversLicenseCredential" + ] + }, + "format": "ldp_vc" + } + } +}`, server.URL) defer server.Close() @@ -59,18 +77,22 @@ func TestWalletInitiatedInteraction_Flow(t *testing.T) { require.NoError(t, err) require.NotNil(t, issuerMetadata) - supportedCredentials := issuerMetadata.SupportedCredentials() + supportedCredentials := issuerMetadata.CredentialConfigurationsSupported() require.Equal(t, 2, supportedCredentials.Length()) - require.Equal(t, "jwt_vc_json", supportedCredentials.AtIndex(0).Format()) - require.Equal(t, 2, supportedCredentials.AtIndex(0).Types().Length()) - require.Equal(t, "VerifiableCredential", supportedCredentials.AtIndex(0).Types().AtIndex(0)) - require.Equal(t, "UniversityDegreeCredential", supportedCredentials.AtIndex(0).Types().AtIndex(1)) + prc := supportedCredentials.CredentialConfigurationSupported("PermanentResidentCard_jwt_vc_json-ld_v1") - require.Equal(t, "ldp_vc", supportedCredentials.AtIndex(1).Format()) - require.Equal(t, 2, supportedCredentials.AtIndex(1).Types().Length()) - require.Equal(t, "VerifiableCredential", supportedCredentials.AtIndex(1).Types().AtIndex(0)) - require.Equal(t, "DriversLicenseCredential", supportedCredentials.AtIndex(1).Types().AtIndex(1)) + require.Equal(t, "jwt_vc_json-ld", prc.Format()) + require.Equal(t, 2, prc.Types().Length()) + require.Equal(t, "VerifiableCredential", prc.Types().AtIndex(0)) + require.Equal(t, "PermanentResidentCard", prc.Types().AtIndex(1)) + + dlc := supportedCredentials.CredentialConfigurationSupported("DriversLicenseCredential_ldp_vc_v1") + + require.Equal(t, "ldp_vc", dlc.Format()) + require.Equal(t, 2, dlc.Types().Length()) + require.Equal(t, "VerifiableCredential", dlc.Types().AtIndex(0)) + require.Equal(t, "DriversLicenseCredential", dlc.Types().AtIndex(1)) dynamicClientRegistrationSupported, err := interaction.DynamicClientRegistrationSupported() require.NoError(t, err) diff --git a/images/vc-rest/Dockerfile b/images/vc-rest/Dockerfile new file mode 100644 index 00000000..f941defa --- /dev/null +++ b/images/vc-rest/Dockerfile @@ -0,0 +1,33 @@ +# +# Copyright Avast Software. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +ARG GO_VER +ARG GO_ALPINE_VER +ARG ALPINE_VER + +FROM golang:${GO_VER}-alpine${GO_ALPINE_VER} as golang +RUN apk add --no-cache \ + gcc \ + musl-dev \ + git \ + libtool \ + bash; +ADD .build/vcs src/github.com/trustbloc/vcs +WORKDIR src/github.com/trustbloc/vcs +ENV EXECUTABLES go git + +FROM golang as vcs +ARG GO_PROXY +RUN mkdir -p ./.build/bin && \ + cd ./cmd/vc-rest && \ + GOPROXY=${GO_PROXY} go build -o ../../.build/bin/vc-rest main.go + +FROM alpine:${ALPINE_VER} as base +LABEL org.opencontainers.image.source https://github.com/trustbloc/vcs + +COPY --from=vcs /go/src/github.com/trustbloc/vcs/.build/bin/vc-rest /usr/local/bin + +ENTRYPOINT ["vc-rest"] diff --git a/pkg/credentialschema/credentialdisplay.go b/pkg/credentialschema/credentialdisplay.go index 553652ab..16380725 100644 --- a/pkg/credentialschema/credentialdisplay.go +++ b/pkg/credentialschema/credentialdisplay.go @@ -22,7 +22,9 @@ var ( errClaimValueNotFoundInVC error ) -func buildCredentialDisplays(vcs []*verifiable.Credential, credentialsSupported []issuer.SupportedCredential, +func buildCredentialDisplays( + vcs []*verifiable.Credential, + credentialConfigurationsSupported map[issuer.CredentialConfigurationID]*issuer.CredentialConfigurationSupported, preferredLocale, maskingString string, ) ([]CredentialDisplay, error) { var credentialDisplays []CredentialDisplay @@ -41,12 +43,12 @@ func buildCredentialDisplays(vcs []*verifiable.Credential, credentialsSupported var foundMatchingType bool - for i := range credentialsSupported { - if !haveMatchingTypes(&credentialsSupported[i], displayVC.Contents().Types) { + for _, credentialConfigurationSupported := range credentialConfigurationsSupported { + if !haveMatchingTypes(credentialConfigurationSupported, displayVC.Contents().Types) { continue } - credentialDisplay, err := buildCredentialDisplay(&credentialsSupported[i], subject, preferredLocale, + credentialDisplay, err := buildCredentialDisplay(credentialConfigurationSupported, subject, preferredLocale, maskingString) if err != nil { return nil, err @@ -72,18 +74,19 @@ func buildCredentialDisplays(vcs []*verifiable.Credential, credentialsSupported return credentialDisplays, nil } -func buildCredentialOfferingDisplays(offeringTypes [][]string, credentialsSupported []issuer.SupportedCredential, +func buildCredentialOfferingDisplays(offeringTypes [][]string, + credentialConfigurationsSupported map[issuer.CredentialConfigurationID]*issuer.CredentialConfigurationSupported, preferredLocale string, ) []CredentialDisplay { var credentialDisplays []CredentialDisplay for _, vcTypes := range offeringTypes { - for i := range credentialsSupported { - if !haveMatchingTypes(&credentialsSupported[i], vcTypes) { + for _, credentialConfiguration := range credentialConfigurationsSupported { + if !haveMatchingTypes(credentialConfiguration, vcTypes) { continue } - credentialDisplay := &CredentialDisplay{Overview: getOverviewDisplay(&credentialsSupported[i], preferredLocale)} + credentialDisplay := &CredentialDisplay{Overview: getOverviewDisplay(credentialConfiguration, preferredLocale)} credentialDisplays = append(credentialDisplays, *credentialDisplay) @@ -96,7 +99,7 @@ func buildCredentialOfferingDisplays(offeringTypes [][]string, credentialsSuppor // The VC is considered to be a match for the supportedCredential if the VC has at least one type that's the same as // the type specified by the supportCredential (excluding the "VerifiableCredential" type that all VCs have). -func haveMatchingTypes(supportedCredential *issuer.SupportedCredential, vcTypes []string) bool { +func haveMatchingTypes(credentialConfSupported *issuer.CredentialConfigurationSupported, vcTypes []string) bool { for _, typeFromVC := range vcTypes { // We expect the types in the VC and SupportedCredential to always include VerifiableCredential, // so we skip this case. @@ -104,7 +107,7 @@ func haveMatchingTypes(supportedCredential *issuer.SupportedCredential, vcTypes continue } - for _, typeFromSupportedCredential := range supportedCredential.Types { + for _, typeFromSupportedCredential := range credentialConfSupported.CredentialDefinition.Type { if strings.EqualFold(typeFromVC, typeFromSupportedCredential) { return true } @@ -114,15 +117,17 @@ func haveMatchingTypes(supportedCredential *issuer.SupportedCredential, vcTypes return false } -func buildCredentialDisplay(supportedCredential *issuer.SupportedCredential, subject *verifiable.Subject, +func buildCredentialDisplay( + credentialConfigurationSupported *issuer.CredentialConfigurationSupported, + subject *verifiable.Subject, preferredLocale, maskingString string, ) (*CredentialDisplay, error) { - resolvedClaims, err := resolveClaims(supportedCredential, subject, preferredLocale, maskingString) + resolvedClaims, err := resolveClaims(credentialConfigurationSupported, subject, preferredLocale, maskingString) if err != nil { return nil, err } - overview := *getOverviewDisplay(supportedCredential, preferredLocale) + overview := *getOverviewDisplay(credentialConfigurationSupported, preferredLocale) return &CredentialDisplay{Overview: &overview, Claims: resolvedClaims}, nil } @@ -164,12 +169,14 @@ func getSubject(vc *verifiable.Credential) (*verifiable.Subject, error) { return &credentialSubjects[0], nil } -func resolveClaims(supportedCredential *issuer.SupportedCredential, credentialSubject *verifiable.Subject, +func resolveClaims( + credentialConfigurationSupported *issuer.CredentialConfigurationSupported, + credentialSubject *verifiable.Subject, preferredLocale, maskingString string, ) ([]ResolvedClaim, error) { var resolvedClaims []ResolvedClaim - for fieldName, claim := range supportedCredential.CredentialSubject { + for fieldName, claim := range credentialConfigurationSupported.CredentialDefinition.CredentialSubject { resolvedClaim, err := resolveClaim(fieldName, claim, credentialSubject, preferredLocale, maskingString) if err != nil && !errors.Is(err, errNoClaimDisplays) && !errors.Is(err, errClaimValueNotFoundInVC) { return nil, err @@ -307,20 +314,27 @@ func findMatchingClaimValueInMap(claims map[string]interface{}, fieldName string return nil } -func getOverviewDisplay(supportedCredential *issuer.SupportedCredential, +func getOverviewDisplay( + credentialConfigurationSupported *issuer.CredentialConfigurationSupported, preferredLocale string, ) *CredentialOverview { if preferredLocale == "" { - return issuerCredentialDisplayToResolvedCredentialOverview(&supportedCredential.LocalizedCredentialDisplays[0]) + return issuerCredentialDisplayToResolvedCredentialOverview( + &credentialConfigurationSupported.LocalizedCredentialDisplays[0], + ) } - for i := range supportedCredential.LocalizedCredentialDisplays { - if strings.EqualFold(preferredLocale, supportedCredential.LocalizedCredentialDisplays[i].Locale) { - return issuerCredentialDisplayToResolvedCredentialOverview(&supportedCredential.LocalizedCredentialDisplays[i]) + for i := range credentialConfigurationSupported.LocalizedCredentialDisplays { + if strings.EqualFold(preferredLocale, credentialConfigurationSupported.LocalizedCredentialDisplays[i].Locale) { + return issuerCredentialDisplayToResolvedCredentialOverview( + &credentialConfigurationSupported.LocalizedCredentialDisplays[i], + ) } } - return issuerCredentialDisplayToResolvedCredentialOverview(&supportedCredential.LocalizedCredentialDisplays[0]) + return issuerCredentialDisplayToResolvedCredentialOverview( + &credentialConfigurationSupported.LocalizedCredentialDisplays[0], + ) } func issuerCredentialDisplayToResolvedCredentialOverview( diff --git a/pkg/credentialschema/credentialschema.go b/pkg/credentialschema/credentialschema.go index 7da113e9..ffd47c17 100644 --- a/pkg/credentialschema/credentialschema.go +++ b/pkg/credentialschema/credentialschema.go @@ -24,7 +24,7 @@ func Resolve(opts ...ResolveOpt) (*ResolvedDisplayData, error) { maskingString = &defaultMaskingString } - credentialDisplays, err := buildCredentialDisplays(vcs, metadata.CredentialsSupported, preferredLocale, + credentialDisplays, err := buildCredentialDisplays(vcs, metadata.CredentialConfigurationsSupported, preferredLocale, *maskingString) if err != nil { return nil, err @@ -49,6 +49,6 @@ func ResolveCredentialOffer( return &ResolvedDisplayData{ IssuerDisplay: issuerOverview, CredentialDisplays: buildCredentialOfferingDisplays(offeredCredentialTypes, - metadata.CredentialsSupported, preferredLocale), + metadata.CredentialConfigurationsSupported, preferredLocale), } } diff --git a/pkg/credentialschema/credentialschema_test.go b/pkg/credentialschema/credentialschema_test.go index cf5a2c48..9c083e10 100644 --- a/pkg/credentialschema/credentialschema_test.go +++ b/pkg/credentialschema/credentialschema_test.go @@ -139,7 +139,8 @@ func TestResolve(t *testing.T) { //nolint: gocognit // Test file err = json.Unmarshal(sampleIssuerMetadata, &metadata) require.NoError(t, err) - metadata.CredentialsSupported[0].Types[1] = "SomeOtherType" + metadata.CredentialConfigurationsSupported["UniversityDegreeCredential_jwt_vc_json-ld_v1"]. + CredentialDefinition.Type[1] = "SomeOtherType" resolvedDisplayData, errResolve := credentialschema.Resolve( credentialschema.WithCredentials([]*verifiable.Credential{credential}), @@ -430,7 +431,8 @@ func TestResolve(t *testing.T) { //nolint: gocognit // Test file err = json.Unmarshal(sampleIssuerMetadata, &issuerMetadata) require.NoError(t, err) - issuerMetadata.CredentialsSupported[0].CredentialSubject["sensitive_id"] = &issuer.Claim{ + credentialConf := issuerMetadata.CredentialConfigurationsSupported["UniversityDegreeCredential_jwt_vc_json-ld_v1"] + credentialConf.CredentialDefinition.CredentialSubject["sensitive_id"] = &issuer.Claim{ LocalizedClaimDisplays: []issuer.LocalizedClaimDisplay{{}}, Mask: "regex(()", } diff --git a/pkg/credentialschema/testdata/bank_issuer_metadata.json b/pkg/credentialschema/testdata/bank_issuer_metadata.json index 5e88c590..4b5aee2c 100644 --- a/pkg/credentialschema/testdata/bank_issuer_metadata.json +++ b/pkg/credentialschema/testdata/bank_issuer_metadata.json @@ -1,103 +1,104 @@ { - "authorization_server":"http://localhost:8075/oidc/authorize", - "credential_endpoint":"http://localhost:8075/oidc/credential", - "display":[ + "authorization_server": "http://localhost:8075/oidc/authorize", + "credential_endpoint": "http://localhost:8075/oidc/credential", + "display": [ { - "locale":"en-US", - "name":"Bank Issuer" + "locale": "en-US", + "name": "Bank Issuer" } ], - "credentials_supported":[ - { - "id": "VerifiedEmployee", + "credential_configurations_supported": { + "VerifiedEmployee_jwt_vc_json_v1": { "format": "jwt_vc_json", - "types":[ - "VerifiableCredential", - "VerifiedEmployee" - ], - "credentialSubject":{ - "displayName":{ - "display":[ - { - "locale":"en-US", - "name":"Employee" - } - ], - "value_type":"string" - }, - "givenName":{ - "display":[ - { - "locale":"en-US", - "name":"Given Name" - } - ], - "value_type":"string" - }, - "jobTitle":{ - "display":[ - { - "locale":"en-US", - "name":"Job Title" - } - ], - "value_type":"string" - }, - "mail":{ - "display":[ - { - "locale":"en-US", - "name":"Mail" - } - ], - "value_type":"string" - }, - "photo":{ - "display":[ - { - "name":"Photo" - } - ], - "value_type":"image" - }, - "preferredLanguage":{ - "display":[ - { - "locale":"en-US", - "name":"Preferred Language" - } - ], - "value_type":"string" + "credential_definition": { + "credentialSubject": { + "displayName": { + "display": [ + { + "locale": "en-US", + "name": "Employee" + } + ], + "value_type": "string" + }, + "givenName": { + "display": [ + { + "locale": "en-US", + "name": "Given Name" + } + ], + "value_type": "string" + }, + "jobTitle": { + "display": [ + { + "locale": "en-US", + "name": "Job Title" + } + ], + "value_type": "string" + }, + "mail": { + "display": [ + { + "locale": "en-US", + "name": "Mail" + } + ], + "value_type": "string" + }, + "photo": { + "display": [ + { + "name": "Photo" + } + ], + "value_type": "image" + }, + "preferredLanguage": { + "display": [ + { + "locale": "en-US", + "name": "Preferred Language" + } + ], + "value_type": "string" + }, + "surname": { + "display": [ + { + "locale": "en-US", + "name": "Surname" + } + ], + "value_type": "string" + } }, - "surname":{ - "display":[ - { - "locale":"en-US", - "name":"Surname" - } - ], - "value_type":"string" - } + "type": [ + "VerifiableCredential", + "VerifiedEmployee" + ] }, - "cryptographic_binding_methods_supported":[ + "cryptographic_binding_methods_supported": [ "orb" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "ECDSASecp256k1DER" ], - "display":[ + "display": [ { - "background_color":"#12107c", - "locale":"en-US", - "logo":{ - "alt_text":"a square logo of an employee verification", - "url":"https://example.com/public/logo.png" + "background_color": "#12107c", + "locale": "en-US", + "logo": { + "alt_text": "a square logo of an employee verification", + "url": "https://example.com/public/logo.png" }, - "name":"Verified Employee", - "text_color":"#FFFFFF" + "name": "Verified Employee", + "text_color": "#FFFFFF" } ] } - ], - "credential_issuer":"http://localhost:8075/bank_issuer_jwtsd" + }, + "credential_issuer": "http://localhost:8075/bank_issuer_jwtsd" } \ No newline at end of file diff --git a/pkg/credentialschema/testdata/issuer_metadata.json b/pkg/credentialschema/testdata/issuer_metadata.json index f1c5df7b..357f456b 100644 --- a/pkg/credentialschema/testdata/issuer_metadata.json +++ b/pkg/credentialschema/testdata/issuer_metadata.json @@ -1,113 +1,114 @@ { - "credential_issuer":"https://server.example.com", - "authorization_server":"https://server.example.com/oidc/authorize", - "credential_endpoint":"https://server.example.com/oidc/credential", - "display":[ + "credential_issuer": "https://server.example.com", + "authorization_server": "https://server.example.com/oidc/authorize", + "credential_endpoint": "https://server.example.com/oidc/credential", + "display": [ { - "locale":"en-US", - "name":"Example University" + "locale": "en-US", + "name": "Example University" }, { - "name":"サンプル大学", - "locale":"jp-JA" + "name": "サンプル大学", + "locale": "jp-JA" } ], - "credentials_supported":[ - { - "id": "UniversityDegreeCredential", - "format":"jwt_vc_json", - "types":[ - "VerifiableCredential", - "UniversityDegreeCredential" - ], - "credentialSubject":{ - "id":{ - "display":[ - { - "name":"ID", - "locale":"en-US" - } - ], - "value_type":"string", - "order":0 - }, - "given_name":{ - "display":[ - { - "name":"Given Name", - "locale":"en-US" - } - ], - "value_type":"string", - "order":1 - }, - "surname":{ - "display":[ - { - "name":"Surname", - "locale":"en-US" - } - ], - "value_type":"string", - "order":2 - }, - "gpa":{ - "display":[ - { - "name":"GPA", - "locale":"en-US" - } - ], - "value_type":"number" - }, - "sensitive_id":{ - "display":[ - { - "name":"Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex(^(.*).{4}$)" - }, - "really_sensitive_id":{ - "display":[ - { - "name":"Really Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex((.*))" + "credential_configurations_supported": { + "UniversityDegreeCredential_jwt_vc_json-ld_v1": { + "format": "jwt_vc_json", + "credential_definition": { + "credentialSubject": { + "id": { + "display": [ + { + "name": "ID", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 0 + }, + "given_name": { + "display": [ + { + "name": "Given Name", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 1 + }, + "surname": { + "display": [ + { + "name": "Surname", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 2 + }, + "gpa": { + "display": [ + { + "name": "GPA", + "locale": "en-US" + } + ], + "value_type": "number" + }, + "sensitive_id": { + "display": [ + { + "name": "Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex(^(.*).{4}$)" + }, + "really_sensitive_id": { + "display": [ + { + "name": "Really Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex((.*))" + }, + "chemistry": { + "display": [ + { + "name": "Chemistry Final Grade", + "locale": "en-US" + } + ], + "value_type": "number" + } }, - "chemistry":{ - "display":[ - { - "name":"Chemistry Final Grade", - "locale":"en-US" - } - ], - "value_type":"number" - } + "type": [ + "VerifiableCredential", + "UniversityDegreeCredential" + ] }, - "cryptographic_binding_methods_supported":[ + "cryptographic_binding_methods_supported": [ "ion" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "ECDSASecp256k1DER" ], - "display":[ + "display": [ { - "name":"University Credential", - "locale":"en-US", - "logo":{ - "url":"https://exampleuniversity.com/public/logo.png", - "alt_text":"a square logo of a university" + "name": "University Credential", + "locale": "en-US", + "logo": { + "url": "https://exampleuniversity.com/public/logo.png", + "alt_text": "a square logo of a university" }, - "background_color":"#12107c", - "text_color":"#FFFFFF" + "background_color": "#12107c", + "text_color": "#FFFFFF" } ] } - ] + } } \ No newline at end of file diff --git a/pkg/credentialschema/testdata/issuer_metadata_without_claims_display.json b/pkg/credentialschema/testdata/issuer_metadata_without_claims_display.json index c58640e2..d3089299 100644 --- a/pkg/credentialschema/testdata/issuer_metadata_without_claims_display.json +++ b/pkg/credentialschema/testdata/issuer_metadata_without_claims_display.json @@ -1,46 +1,47 @@ { - "credential_issuer":"https://server.example.com", - "authorization_server":"https://server.example.com/oidc/authorize", - "credential_endpoint":"https://server.example.com/oidc/credential", - "display":[ + "credential_issuer": "https://server.example.com", + "authorization_server": "https://server.example.com/oidc/authorize", + "credential_endpoint": "https://server.example.com/oidc/credential", + "display": [ { - "locale":"en-US", - "name":"Example University" + "locale": "en-US", + "name": "Example University" }, { - "name":"サンプル大学", - "locale":"jp-JA" + "name": "サンプル大学", + "locale": "jp-JA" } ], - "credentials_supported":[ - { - "id":"UniversityDegreeCredential", - "format":"jwt_vc_json", - "types":[ - "VerifiableCredential", - "UniversityDegreeCredential" - ], - "credentialSubject":{ - "id":{} + "credential_configurations_supported": { + "UniversityDegreeCredential_jwt_vc_json_v1": { + "format": "jwt_vc_json", + "credential_definition": { + "credentialSubject": { + "id": {} + }, + "type": [ + "VerifiableCredential", + "UniversityDegreeCredential" + ] }, - "cryptographic_binding_methods_supported":[ + "cryptographic_binding_methods_supported": [ "ion" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "ECDSASecp256k1DER" ], - "display":[ + "display": [ { - "name":"University Credential", - "locale":"en-US", - "logo":{ - "url":"https://exampleuniversity.com/public/logo.png", - "alt_text":"a square logo of a university" + "name": "University Credential", + "locale": "en-US", + "logo": { + "url": "https://exampleuniversity.com/public/logo.png", + "alt_text": "a square logo of a university" }, - "background_color":"#12107c", - "text_color":"#FFFFFF" + "background_color": "#12107c", + "text_color": "#FFFFFF" } ] } - ] + } } \ No newline at end of file diff --git a/pkg/internal/issuermetadata/issuermetadata.go b/pkg/internal/issuermetadata/issuermetadata.go index 829341a0..b99972ab 100644 --- a/pkg/internal/issuermetadata/issuermetadata.go +++ b/pkg/internal/issuermetadata/issuermetadata.go @@ -61,18 +61,22 @@ func responseBytesToIssuerMetadataObject(responseBytes []byte, // First, try parsing directly as JSON. err := json.Unmarshal(responseBytes, &metadata) - if err == nil { - return &metadata, nil + if err != nil { + return nil, fmt.Errorf("decode metadata: %w", err) + } + + if len(metadata.SignedMetadata) > 0 { + return issuerMetadataObjectFromJWT(metadata.SignedMetadata, signatureVerifier, err) } - return issuerMetadataObjectFromJWT(responseBytes, signatureVerifier, err) + return &metadata, nil } // errUnmarshal is the error that happened when the response bytes couldn't be unmarshalled into the issuer metadata // struct directly. It's passed here so that it can be included in the error message in case the response // is also not a JWT. This gives the caller additional information that can help them to more easily debug the cause // of the parsing failure. -func issuerMetadataObjectFromJWT(responseBytes []byte, signatureVerifier jwt.ProofChecker, +func issuerMetadataObjectFromJWT(signedMetadata string, signatureVerifier jwt.ProofChecker, errUnmarshal error, ) (*issuer.Metadata, error) { var metadata issuer.Metadata @@ -84,7 +88,7 @@ func issuerMetadataObjectFromJWT(responseBytes []byte, signatureVerifier jwt.Pro return nil, errors.New("missing signature verifier") } - jsonWebToken, _, errParseJWT := jwt.ParseAndCheckProof(string(responseBytes), signatureVerifier, false) + jsonWebToken, _, errParseJWT := jwt.ParseAndCheckProof(signedMetadata, signatureVerifier, false) if errParseJWT != nil { return nil, fmt.Errorf("failed to parse the response from the issuer's OpenID Credential Issuer "+ "endpoint as JSON or as a JWT: %w", errors.Join(errUnmarshal, errParseJWT)) diff --git a/pkg/internal/issuermetadata/issuermetadata_test.go b/pkg/internal/issuermetadata/issuermetadata_test.go index 8554f09a..55234776 100644 --- a/pkg/internal/issuermetadata/issuermetadata_test.go +++ b/pkg/internal/issuermetadata/issuermetadata_test.go @@ -77,7 +77,8 @@ func TestGet(t *testing.T) { require.NoError(t, err) require.NotNil(t, issuerMetadata) - displayNameClaim, exists := issuerMetadata.CredentialsSupported[0].CredentialSubject["displayName"] + credentialConf := issuerMetadata.CredentialConfigurationsSupported["VerifiedEmployee_ldp_vc_v1"] + displayNameClaim, exists := credentialConf.CredentialDefinition.CredentialSubject["displayName"] require.True(t, exists) require.NotNil(t, displayNameClaim.Order) @@ -86,7 +87,7 @@ func TestGet(t *testing.T) { require.NoError(t, err) require.Equal(t, 3, order) - jobTitleClaim, exists := issuerMetadata.CredentialsSupported[0].CredentialSubject["jobTitle"] + jobTitleClaim, exists := credentialConf.CredentialDefinition.CredentialSubject["jobTitle"] require.True(t, exists) require.Nil(t, jobTitleClaim.Order) @@ -123,7 +124,10 @@ func TestGet(t *testing.T) { require.NoError(t, err) require.NotNil(t, issuerMetadata) - displayNameClaim, exists := issuerMetadata.CredentialsSupported[0].CredentialSubject["displayName"] + credentialConf := issuerMetadata.CredentialConfigurationsSupported["VerifiedEmployee_ldp_vc_v1"] + credentialDefinition := credentialConf.CredentialDefinition + + displayNameClaim, exists := credentialDefinition.CredentialSubject["displayName"] require.True(t, exists) require.NotNil(t, displayNameClaim.Order) @@ -132,7 +136,7 @@ func TestGet(t *testing.T) { require.NoError(t, err) require.Equal(t, 3, order) - jobTitleClaim, exists := issuerMetadata.CredentialsSupported[0].CredentialSubject["jobTitle"] + jobTitleClaim, exists := credentialDefinition.CredentialSubject["jobTitle"] require.True(t, exists) require.Nil(t, jobTitleClaim.Order) @@ -162,7 +166,7 @@ func TestGet(t *testing.T) { require.Nil(t, issuerMetadata) }) t.Run("Missing signature verifier", func(t *testing.T) { - issuerServerHandler := &mockIssuerServerHandler{issuerMetadata: "invalid"} + issuerServerHandler := &mockIssuerServerHandler{issuerMetadata: `{"signed_metadata": "a.b"}`} server := httptest.NewServer(issuerServerHandler) defer server.Close() @@ -185,7 +189,7 @@ func TestGet(t *testing.T) { require.Nil(t, issuerMetadata) }) t.Run("Fail to parse", func(t *testing.T) { - issuerServerHandler := &mockIssuerServerHandler{} + issuerServerHandler := &mockIssuerServerHandler{issuerMetadata: `{"signed_metadata": "a.b"}`} server := httptest.NewServer(issuerServerHandler) defer server.Close() @@ -193,7 +197,7 @@ func TestGet(t *testing.T) { issuerMetadata, err := issuermetadata.Get(server.URL, http.DefaultClient, nil, "", &mockVerifier{}) require.EqualError(t, err, "failed to parse the response from the issuer's OpenID Credential "+ - "Issuer endpoint as JSON or as a JWT: unexpected end of JSON input\nJWT of compacted JWS form is "+ + "Issuer endpoint as JSON or as a JWT: JWT of compacted JWS form is "+ "supported only") require.Nil(t, issuerMetadata) }) diff --git a/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.json b/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.json index 5e5a9781..d5fd407b 100644 --- a/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.json +++ b/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.json @@ -1,101 +1,102 @@ { - "credential_issuer":"https://server.example.com", - "authorization_server":"https://server.example.com/oidc/authorize", - "credential_endpoint":"https://server.example.com/oidc/credential", - "display":[ + "credential_issuer": "https://server.example.com", + "authorization_server": "https://server.example.com/oidc/authorize", + "credential_endpoint": "https://server.example.com/oidc/credential", + "display": [ { - "locale":"en-US", - "name":"Example University" + "locale": "en-US", + "name": "Example University" }, { - "name":"サンプル大学", - "locale":"jp-JA" + "name": "サンプル大学", + "locale": "jp-JA" } ], - "credentials_supported":[ - { - "credentialSubject":{ - "displayName":{ - "display":[ - { - "locale":"en-US", - "name":"Employee" - } - ], - "order":3 - }, - "givenName":{ - "display":[ - { - "locale":"en-US", - "name":"Given Name" - } - ] - }, - "jobTitle":{ - "display":[ - { - "locale":"en-US", - "name":"Job Title" - } - ] - }, - "mail":{ - "display":[ - { - "locale":"en-US", - "name":"Mail" - } - ] - }, - "photo":{ - "display":[ - { - "name":"Photo" - } - ] - }, - "preferredLanguage":{ - "display":[ - { - "locale":"en-US", - "name":"Preferred Language" - } - ] - }, - "surname":{ - "display":[ - { - "locale":"en-US", - "name":"Surname" - } - ] - } - }, - "cryptographic_binding_methods_supported":[ + "credential_configurations_supported": { + "VerifiedEmployee_ldp_vc_v1": { + "cryptographic_binding_methods_supported": [ "jwk" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "ECDSAP256DER" ], - "display":[ + "display": [ { - "background_color":"#12107c", - "locale":"en-US", - "logo":{ - "alt_text":"a square logo of a employee verification", - "url":"https://example.com/public/logo.png" + "background_color": "#12107c", + "locale": "en-US", + "logo": { + "alt_text": "a square logo of a employee verification", + "url": "https://example.com/public/logo.png" }, - "name":"Verified Employee", - "text_color":"#FFFFFF" + "name": "Verified Employee", + "text_color": "#FFFFFF" } ], - "format":"ldp_vc", - "id":"VerifiedEmployee_LDP", - "types":[ - "VerifiableCredential", - "VerifiedEmployee" - ] + "format": "ldp_vc", + "credential_definition": { + "credentialSubject": { + "displayName": { + "display": [ + { + "locale": "en-US", + "name": "Employee" + } + ], + "order": 3 + }, + "givenName": { + "display": [ + { + "locale": "en-US", + "name": "Given Name" + } + ] + }, + "jobTitle": { + "display": [ + { + "locale": "en-US", + "name": "Job Title" + } + ] + }, + "mail": { + "display": [ + { + "locale": "en-US", + "name": "Mail" + } + ] + }, + "photo": { + "display": [ + { + "name": "Photo" + } + ] + }, + "preferredLanguage": { + "display": [ + { + "locale": "en-US", + "name": "Preferred Language" + } + ] + }, + "surname": { + "display": [ + { + "locale": "en-US", + "name": "Surname" + } + ] + } + }, + "type": [ + "VerifiableCredential", + "VerifiedEmployee" + ] + } } - ] + } } \ No newline at end of file diff --git a/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.jwt b/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.jwt index 7fe40042..377759a4 100644 --- a/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.jwt +++ b/pkg/internal/issuermetadata/testdata/sample_issuer_metadata.jwt @@ -1 +1,3 @@ -eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSN6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIn0.eyJpYXQiOjE2OTQ1ODE5ODIsImlzcyI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSIsInN1YiI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSIsIndlbGxfa25vd25fb3BlbmlkX2lzc3Vlcl9jb25maWd1cmF0aW9uIjp7ImF1dGhvcml6YXRpb25fc2VydmVyIjoiaHR0cHM6Ly9hcGktZ2F0ZXdheS50cnVzdGJsb2MubG9jYWw6NTU2Ni9vaWRjL2F1dGhvcml6ZSIsImNyZWRlbnRpYWxfZW5kcG9pbnQiOiJodHRwczovL2FwaS1nYXRld2F5LnRydXN0YmxvYy5sb2NhbDo1NTY2L29pZGMvY3JlZGVudGlhbCIsImNyZWRlbnRpYWxfaXNzdWVyIjoiaHR0cHM6Ly9hcGktZ2F0ZXdheS50cnVzdGJsb2MubG9jYWw6NTU2Ni9pc3N1ZXIvaV9teXByb2ZpbGVfY210cl9wMjU2X2xkcC92MS4wIiwiY3JlZGVudGlhbHNfc3VwcG9ydGVkIjpbeyJjcmVkZW50aWFsU3ViamVjdCI6eyJkaXNwbGF5TmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJFbXBsb3llZSJ9XX0sImdpdmVuTmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJHaXZlbiBOYW1lIn1dfSwiam9iVGl0bGUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiSm9iIFRpdGxlIn1dfSwibWFpbCI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJNYWlsIn1dfSwicGhvdG8iOnsiZGlzcGxheSI6W3sibmFtZSI6IlBob3RvIn1dfSwicHJlZmVycmVkTGFuZ3VhZ2UiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiUHJlZmVycmVkIExhbmd1YWdlIn1dfSwic3VybmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJTdXJuYW1lIn1dfX0sImNyeXB0b2dyYXBoaWNfYmluZGluZ19tZXRob2RzX3N1cHBvcnRlZCI6WyJqd2siXSwiY3J5cHRvZ3JhcGhpY19zdWl0ZXNfc3VwcG9ydGVkIjpbIkVDRFNBUDI1NkRFUiJdLCJkaXNwbGF5IjpbeyJiYWNrZ3JvdW5kX2NvbG9yIjoiIzEyMTA3YyIsImxvY2FsZSI6ImVuLVVTIiwibG9nbyI6eyJhbHRfdGV4dCI6ImEgc3F1YXJlIGxvZ28gb2YgYSBlbXBsb3llZSB2ZXJpZmljYXRpb24iLCJ1cmwiOiJodHRwczovL2V4YW1wbGUuY29tL3B1YmxpYy9sb2dvLnBuZyJ9LCJuYW1lIjoiVmVyaWZpZWQgRW1wbG95ZWUiLCJ0ZXh0X2NvbG9yIjoiI0ZGRkZGRiJ9XSwiZm9ybWF0IjoibGRwX3ZjIiwiaWQiOiJWZXJpZmllZEVtcGxveWVlX0xEUCIsInR5cGVzIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpZWRFbXBsb3llZSJdfV0sImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6ImlfbXlwcm9maWxlX2NtdHJfcDI1Nl9sZHAiLCJ1cmwiOiJodHRwOi8vdmMtcmVzdC1lY2hvLnRydXN0YmxvYy5sb2NhbDo4MDc1In1dfX0.MEYCIQD6KOZns0aPMM5BD1qXwZRmUd2K0MBS31QvSXJrM2Qw0gIhAMXoDx5ApTlHAU1o940kRiR0u-dVl9LBf6m3TMqmFL7x +{ + "signed_metadata": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSN6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIn0.eyJpYXQiOjE2OTQ1ODE5ODIsImlzcyI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSIsInN1YiI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSIsIndlbGxfa25vd25fb3BlbmlkX2lzc3Vlcl9jb25maWd1cmF0aW9uIjp7ImF1dGhvcml6YXRpb25fc2VydmVyIjoiaHR0cHM6Ly9hcGktZ2F0ZXdheS50cnVzdGJsb2MubG9jYWw6NTU2Ni9vaWRjL2F1dGhvcml6ZSIsImNyZWRlbnRpYWxfZW5kcG9pbnQiOiJodHRwczovL2FwaS1nYXRld2F5LnRydXN0YmxvYy5sb2NhbDo1NTY2L29pZGMvY3JlZGVudGlhbCIsImNyZWRlbnRpYWxfaXNzdWVyIjoiaHR0cHM6Ly9hcGktZ2F0ZXdheS50cnVzdGJsb2MubG9jYWw6NTU2Ni9pc3N1ZXIvaV9teXByb2ZpbGVfY210cl9wMjU2X2xkcC92MS4wIiwiY3JlZGVudGlhbHNfc3VwcG9ydGVkIjpbeyJjcmVkZW50aWFsU3ViamVjdCI6eyJkaXNwbGF5TmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJFbXBsb3llZSJ9XX0sImdpdmVuTmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJHaXZlbiBOYW1lIn1dfSwiam9iVGl0bGUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiSm9iIFRpdGxlIn1dfSwibWFpbCI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJNYWlsIn1dfSwicGhvdG8iOnsiZGlzcGxheSI6W3sibmFtZSI6IlBob3RvIn1dfSwicHJlZmVycmVkTGFuZ3VhZ2UiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiUHJlZmVycmVkIExhbmd1YWdlIn1dfSwic3VybmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJTdXJuYW1lIn1dfX0sImNyeXB0b2dyYXBoaWNfYmluZGluZ19tZXRob2RzX3N1cHBvcnRlZCI6WyJqd2siXSwiY3J5cHRvZ3JhcGhpY19zdWl0ZXNfc3VwcG9ydGVkIjpbIkVDRFNBUDI1NkRFUiJdLCJkaXNwbGF5IjpbeyJiYWNrZ3JvdW5kX2NvbG9yIjoiIzEyMTA3YyIsImxvY2FsZSI6ImVuLVVTIiwibG9nbyI6eyJhbHRfdGV4dCI6ImEgc3F1YXJlIGxvZ28gb2YgYSBlbXBsb3llZSB2ZXJpZmljYXRpb24iLCJ1cmwiOiJodHRwczovL2V4YW1wbGUuY29tL3B1YmxpYy9sb2dvLnBuZyJ9LCJuYW1lIjoiVmVyaWZpZWQgRW1wbG95ZWUiLCJ0ZXh0X2NvbG9yIjoiI0ZGRkZGRiJ9XSwiZm9ybWF0IjoibGRwX3ZjIiwiaWQiOiJWZXJpZmllZEVtcGxveWVlX0xEUCIsInR5cGVzIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpZWRFbXBsb3llZSJdfV0sImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6ImlfbXlwcm9maWxlX2NtdHJfcDI1Nl9sZHAiLCJ1cmwiOiJodHRwOi8vdmMtcmVzdC1lY2hvLnRydXN0YmxvYy5sb2NhbDo4MDc1In1dfX0.MEYCIQD6KOZns0aPMM5BD1qXwZRmUd2K0MBS31QvSXJrM2Qw0gIhAMXoDx5ApTlHAU1o940kRiR0u-dVl9LBf6m3TMqmFL7x" +} \ No newline at end of file diff --git a/pkg/internal/issuermetadata/testdata/sample_issuer_metadata_with_order.jwt b/pkg/internal/issuermetadata/testdata/sample_issuer_metadata_with_order.jwt index c6b37127..f5466152 100644 --- a/pkg/internal/issuermetadata/testdata/sample_issuer_metadata_with_order.jwt +++ b/pkg/internal/issuermetadata/testdata/sample_issuer_metadata_with_order.jwt @@ -1 +1,3 @@ -eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSN6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIn0.eyJpYXQiOiIxNjk0NTgxOTgyIiwiaXNzIjoiZGlkOmtleTp6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIiwic3ViIjoiZGlkOmtleTp6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIiwid2VsbF9rbm93bl9vcGVuaWRfaXNzdWVyX2NvbmZpZ3VyYXRpb24iOnsiYXV0aG9yaXphdGlvbl9zZXJ2ZXIiOiJodHRwczovL2FwaS1nYXRld2F5LnRydXN0YmxvYy5sb2NhbDo1NTY2L29pZGMvYXV0aG9yaXplIiwiY3JlZGVudGlhbF9lbmRwb2ludCI6Imh0dHBzOi8vYXBpLWdhdGV3YXkudHJ1c3RibG9jLmxvY2FsOjU1NjYvb2lkYy9jcmVkZW50aWFsIiwiY3JlZGVudGlhbF9pc3N1ZXIiOiJodHRwczovL2FwaS1nYXRld2F5LnRydXN0YmxvYy5sb2NhbDo1NTY2L2lzc3Vlci9pX215cHJvZmlsZV9jbXRyX3AyNTZfbGRwL3YxLjAiLCJjcmVkZW50aWFsc19zdXBwb3J0ZWQiOlt7ImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRpc3BsYXlOYW1lIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6IkVtcGxveWVlIn1dLCJvcmRlciI6M30sImdpdmVuTmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJHaXZlbiBOYW1lIn1dfSwiam9iVGl0bGUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiSm9iIFRpdGxlIn1dfSwibWFpbCI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJNYWlsIn1dfSwicGhvdG8iOnsiZGlzcGxheSI6W3sibmFtZSI6IlBob3RvIn1dfSwicHJlZmVycmVkTGFuZ3VhZ2UiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiUHJlZmVycmVkIExhbmd1YWdlIn1dfSwic3VybmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJTdXJuYW1lIn1dfX0sImNyeXB0b2dyYXBoaWNfYmluZGluZ19tZXRob2RzX3N1cHBvcnRlZCI6WyJqd2siXSwiY3J5cHRvZ3JhcGhpY19zdWl0ZXNfc3VwcG9ydGVkIjpbIkVDRFNBUDI1NkRFUiJdLCJkaXNwbGF5IjpbeyJiYWNrZ3JvdW5kX2NvbG9yIjoiIzEyMTA3YyIsImxvY2FsZSI6ImVuLVVTIiwibG9nbyI6eyJhbHRfdGV4dCI6ImEgc3F1YXJlIGxvZ28gb2YgYSBlbXBsb3llZSB2ZXJpZmljYXRpb24iLCJ1cmwiOiJodHRwczovL2V4YW1wbGUuY29tL3B1YmxpYy9sb2dvLnBuZyJ9LCJuYW1lIjoiVmVyaWZpZWQgRW1wbG95ZWUiLCJ0ZXh0X2NvbG9yIjoiI0ZGRkZGRiJ9XSwiZm9ybWF0IjoibGRwX3ZjIiwiaWQiOiJWZXJpZmllZEVtcGxveWVlX0xEUCIsInR5cGVzIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpZWRFbXBsb3llZSJdfV0sImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6ImlfbXlwcm9maWxlX2NtdHJfcDI1Nl9sZHAiLCJ1cmwiOiJodHRwOi8vdmMtcmVzdC1lY2hvLnRydXN0YmxvYy5sb2NhbDo4MDc1In1dfX0. +{ + "signed_metadata": "eyJhbGciOiJIUzI1NiIsImtpZCI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSN6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIn0.eyJpYXQiOiIxNjk0NTgxOTgyIiwiaXNzIjoiZGlkOmtleTp6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIiwic3ViIjoiZGlkOmtleTp6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIiwid2VsbF9rbm93bl9vcGVuaWRfaXNzdWVyX2NvbmZpZ3VyYXRpb24iOnsiYXV0aG9yaXphdGlvbl9zZXJ2ZXIiOiJodHRwczovL2FwaS1nYXRld2F5LnRydXN0YmxvYy5sb2NhbDo1NTY2L29pZGMvYXV0aG9yaXplIiwiY3JlZGVudGlhbF9lbmRwb2ludCI6Imh0dHBzOi8vYXBpLWdhdGV3YXkudHJ1c3RibG9jLmxvY2FsOjU1NjYvb2lkYy9jcmVkZW50aWFsIiwiY3JlZGVudGlhbF9pc3N1ZXIiOiJodHRwczovL2FwaS1nYXRld2F5LnRydXN0YmxvYy5sb2NhbDo1NTY2L2lzc3Vlci9pX215cHJvZmlsZV9jbXRyX3AyNTZfbGRwL3YxLjAiLCJjcmVkZW50aWFsX2NvbmZpZ3VyYXRpb25zX3N1cHBvcnRlZCI6eyJWZXJpZmllZEVtcGxveWVlX2xkcF92Y192MSI6eyJjcnlwdG9ncmFwaGljX2JpbmRpbmdfbWV0aG9kc19zdXBwb3J0ZWQiOlsiandrIl0sImNyeXB0b2dyYXBoaWNfc3VpdGVzX3N1cHBvcnRlZCI6WyJFQ0RTQVAyNTZERVIiXSwiZGlzcGxheSI6W3siYmFja2dyb3VuZF9jb2xvciI6IiMxMjEwN2MiLCJsb2NhbGUiOiJlbi1VUyIsImxvZ28iOnsiYWx0X3RleHQiOiJhIHNxdWFyZSBsb2dvIG9mIGEgZW1wbG95ZWUgdmVyaWZpY2F0aW9uIiwidXJsIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9wdWJsaWMvbG9nby5wbmcifSwibmFtZSI6IlZlcmlmaWVkIEVtcGxveWVlIiwidGV4dF9jb2xvciI6IiNGRkZGRkYifV0sImZvcm1hdCI6ImxkcF92YyIsImNyZWRlbnRpYWxfZGVmaW5pdGlvbiI6eyJjcmVkZW50aWFsU3ViamVjdCI6eyJkaXNwbGF5TmFtZSI6eyJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJFbXBsb3llZSJ9XSwib3JkZXIiOjN9LCJnaXZlbk5hbWUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiR2l2ZW4gTmFtZSJ9XX0sImpvYlRpdGxlIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6IkpvYiBUaXRsZSJ9XX0sIm1haWwiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiTWFpbCJ9XX0sInBob3RvIjp7ImRpc3BsYXkiOlt7Im5hbWUiOiJQaG90byJ9XX0sInByZWZlcnJlZExhbmd1YWdlIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6IlByZWZlcnJlZCBMYW5ndWFnZSJ9XX0sInN1cm5hbWUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiU3VybmFtZSJ9XX19LCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpZWRFbXBsb3llZSJdfX19LCJkaXNwbGF5IjpbeyJsb2NhbGUiOiJlbi1VUyIsIm5hbWUiOiJpX215cHJvZmlsZV9jbXRyX3AyNTZfbGRwIiwidXJsIjoiaHR0cDovL3ZjLXJlc3QtZWNoby50cnVzdGJsb2MubG9jYWw6ODA3NSJ9XX19.EvZ6wWWu_z-GlaNfkK0Wy7zeLdBS_NGzMBQyiIFMaaU" +} \ No newline at end of file diff --git a/pkg/internal/issuermetadata/testdata/sample_jwt_without_issuer_metadata.jwt b/pkg/internal/issuermetadata/testdata/sample_jwt_without_issuer_metadata.jwt index dc71c646..19747846 100644 --- a/pkg/internal/issuermetadata/testdata/sample_jwt_without_issuer_metadata.jwt +++ b/pkg/internal/issuermetadata/testdata/sample_jwt_without_issuer_metadata.jwt @@ -1 +1,3 @@ -eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSN6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIn0.eyJpYXQiOjE2OTQ1ODE5ODIsImlzcyI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSIsInN1YiI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSJ9.HAzAv9Vd8VE3iEkK600cCCuROqEtx_RNtaFl4_dWsuWOQJXrjj67xlQKs8OqPUsCL3GpO-DKOAoG4mzspQFlRg \ No newline at end of file +{ + "signed_metadata": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSN6RG5hZXA0SFp3amdidEQyWHUyZFBMZ3p5Z3dLS2cxQ05CTkVYTjFuNWFUYlFzQktVIn0.eyJpYXQiOjE2OTQ1ODE5ODIsImlzcyI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSIsInN1YiI6ImRpZDprZXk6ekRuYWVwNEhad2pnYnREMlh1MmRQTGd6eWd3S0tnMUNOQk5FWE4xbjVhVGJRc0JLVSJ9.HAzAv9Vd8VE3iEkK600cCCuROqEtx_RNtaFl4_dWsuWOQJXrjj67xlQKs8OqPUsCL3GpO-DKOAoG4mzspQFlRg" +} \ No newline at end of file diff --git a/pkg/models/issuer/metadata.go b/pkg/models/issuer/metadata.go index cdef4a2a..1c1c77a5 100644 --- a/pkg/models/issuer/metadata.go +++ b/pkg/models/issuer/metadata.go @@ -12,16 +12,160 @@ import ( "strconv" ) +// CredentialConfigurationID is an alias for type "string" introduced to simplify understanding of the specification. +type CredentialConfigurationID = string + // Metadata represents metadata about an issuer as obtained from their .well-known OpenID configuration. type Metadata struct { - CredentialIssuer string `json:"credential_issuer,omitempty"` - AuthorizationServer string `json:"authorization_endpoint,omitempty"` - CredentialEndpoint string `json:"credential_endpoint,omitempty"` - CredentialsSupported []SupportedCredential `json:"credentials_supported,omitempty"` + jwtKID *string + + // URL of the OP's OAuth 2.0 Authorization Endpoint. + AuthorizationServer string `json:"authorization_endpoint,omitempty"` + + // URL of the Credential Issuer's Batch Credential Endpoint. This URL MUST use the https scheme and MAY contain + // port, path and query parameter components. + // If omitted, the Credential Issuer does not support the Batch Credential Endpoint. + BatchCredentialEndpoint string `json:"batch_credential_endpoint,omitempty"` + + // URL of the acknowledgement endpoint. + CredentialAckEndpoint string `json:"credential_ack_endpoint,omitempty"` + + // An object that describes specifics of the Credential that the Credential Issuer supports issuance of. + // This object contains a list of name/value pairs, where each name is a unique identifier + // of the supported credential being described. + CredentialConfigurationsSupported map[CredentialConfigurationID]*CredentialConfigurationSupported `json:"credential_configurations_supported,omitempty"` //nolint:lll + + // URL of the Credential Issuer's Credential Endpoint. This URL MUST use the https scheme and MAY contain + // port, path and query parameter components. + CredentialEndpoint string `json:"credential_endpoint,omitempty"` + + // Boolean value specifying whether the Credential Issuer supports returning credential_identifiers parameter + // in the authorization_details Token Response parameter, with true indicating support. + // If omitted, the default value is false. + CredentialIdentifiersSupported *bool `json:"credential_identifiers_supported,omitempty"` + + // The Credential Issuer's identifier. + CredentialIssuer string `json:"credential_issuer,omitempty"` + + // Object containing information about whether the Credential Issuer supports encryption of the Credential + // and Batch Credential Response on top of TLS + CredentialResponseEncryption *CredentialResponseEncryptionSupported `json:"credential_response_encryption,omitempty"` + + // URL of the Credential Issuer's Deferred Credential Endpoint. This URL MUST use the https scheme and MAY contain + // port, path, and query parameter components. + // If omitted, the Credential Issuer does not support the Deferred Credential Endpoint. + DeferredCredentialEndpoint string `json:"deferred_credential_endpoint,omitempty"` + + // An array of objects, where each object contains display properties of a Credential Issuer for a certain language. LocalizedIssuerDisplays []LocalizedIssuerDisplay `json:"display,omitempty"` - TokenEndpoint string `json:"token_endpoint,omitempty"` - CredentialAckEndpoint string `json:"credential_ack_endpoint,omitempty"` - jwtKID *string + + // JSON array containing a list of the OAuth 2.0 Grant Type values that this OP supports. + GrantTypesSupported []string `json:"grant_types_supported,omitempty"` + + // URL of the Credential Issuer's Notification Endpoint. This URL MUST use the https scheme and MAY contain + // port, path, and query parameter components. + // If omitted, the Credential Issuer does not support the Notification Endpoint. + NotificationEndpoint string `json:"notification_endpoint,omitempty"` + + // Boolean indicating whether the issuer accepts a Token Request with a Pre-Authorized Code but without a client id. + // The default is false. + PreAuthorizedGrantAnonymousAccessSupported *bool `json:"pre-authorized_grant_anonymous_access_supported,omitempty"` + + // URL of the OP's Dynamic Client Registration Endpoint. + RegistrationEndpoint string `json:"registration_endpoint,omitempty"` + + // JSON array containing a list of the OAuth 2.0 response_type values that this OP supports. + ResponseTypesSupported []string `json:"response_types_supported,omitempty"` + + // JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this server supports. + ScopesSupported []string `json:"scopes_supported,omitempty"` + + // String that is a signed JWT. This JWT contains Credential Issuer metadata parameters as claims. + SignedMetadata string `json:"signed_metadata,omitempty"` + + // URL of the OP's OAuth 2.0 Token Endpoint. + TokenEndpoint string `json:"token_endpoint,omitempty"` + + // JSON array containing a list of client authentication methods supported by this token endpoint. Default is "none". + TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"` +} + +// CredentialConfigurationSupported describes specifics of the Credential that +// the Credential Issuer supports issuance of. +type CredentialConfigurationSupported struct { + // For mso_mdoc and vc+sd-jwt vc only. Object containing a list of name/value pairs, + // where each name identifies a claim about the subject offered in the Credential. + // The value can be another such object (nested data structures), or an array of such objects. + Claims *map[string]interface{} `json:"claims,omitempty"` + + // Object containing the detailed description of the credential type. + CredentialDefinition *CredentialDefinition `json:"credential_definition,omitempty"` + + // Array of case-sensitive strings that identify how the Credential is bound to the identifier of the End-User + // who possesses the Credential. + CryptographicBindingMethodsSupported []string `json:"cryptographic_binding_methods_supported,omitempty"` + + // Array of case-sensitive strings that identify the cryptographic suites + // that are supported for the cryptographic_binding_methods_supported. + CryptographicSuitesSupported []string `json:"cryptographic_suites_supported,omitempty"` + + // An array of objects, where each object contains the display properties of the + // supported credential for a certain language. + LocalizedCredentialDisplays []LocalizedCredentialDisplay `json:"display,omitempty"` + + // For mso_mdoc vc only. String identifying the Credential type, as defined in [ISO.18013-5]. + Doctype string `json:"doctype,omitempty"` + + // A JSON string identifying the format of this credential, i.e., jwt_vc_json or ldp_vc. + // Depending on the format value, the object contains further elements defining the type and (optionally) + // particular claims the credential MAY contain and information about how to display the credential. + Format string `json:"format"` + + // Array of the claim name values that lists them in the order they should be displayed by the Wallet. + Order []string `json:"order,omitempty"` + + // A JSON array of case-sensitive strings, each representing proof_type that the Credential Issuer supports. + // If omitted, the default value is jwt. + ProofTypes []string `json:"proof_types,omitempty"` + + // A JSON string identifying the scope value that this Credential Issuer supports for this particular credential. + Scope string `json:"scope,omitempty"` + + // For vc+sd-jwt vc only. String designating the type of Credential, + // as defined in https://datatracker.ietf.org/doc/html/draft-ietf-oauth-sd-jwt-vc-01 + Vct string `json:"vct,omitempty"` +} + +// CredentialDefinition containing the detailed description of the credential type. +type CredentialDefinition struct { + // For ldp_vc only. Array as defined in https://www.w3.org/TR/vc-data-model/#contexts. + Context []string `json:"@context,omitempty"` + + // An object containing a list of name/value pairs, where each name identifies a claim offered in the Credential. + // The value can be another such object (nested data structures), or an array of such objects. + CredentialSubject map[string]*Claim `json:"credentialSubject,omitempty"` + + // Array designating the types a certain credential type supports. + Type []string `json:"type"` +} + +// CredentialResponseEncryptionSupported containing information about whether the Credential Issuer +// supports encryption of the Credential and Batch Credential Response on top of TLS. +type CredentialResponseEncryptionSupported struct { + // Array containing a list of the JWE [RFC7516] encryption algorithms (alg values) [RFC7518] supported by the + // Credential and Batch Credential Endpoint to encode the Credential or Batch Credential Response in a JWT [RFC7519]. + AlgValuesSupported []string `json:"alg_values_supported"` + + // Array containing a list of the JWE [RFC7516] encryption algorithms (enc values) [RFC7518] + // supported by the Credential and Batch Credential Endpoint to encode the Credential or + // Batch Credential Response in a JWT [RFC7519]. + EncValuesSupported []string `json:"enc_values_supported"` + + // Boolean value specifying whether the Credential Issuer requires the additional encryption on top of TLS + // for the Credential Response. If the value is true, the Credential Issuer requires encryption for + // every Credential Response and therefore the Wallet MUST provide encryption keys in the Credential Request. + // If the value is false, the Wallet MAY choose whether it provides encryption keys or not. + EncryptionRequired bool `json:"encryption_required"` } // GetJWTKID returns the jwtKID field. This is exposed via this method instead of with an exported field because @@ -36,17 +180,6 @@ func (m *Metadata) SetJWTKID(jwtKID string) { m.jwtKID = &jwtKID } -// SupportedCredential represents metadata about a credential type that a credential issuer can issue. -type SupportedCredential struct { - Format string `json:"format,omitempty"` - Types []string `json:"types,omitempty"` - ID string `json:"id,omitempty"` - LocalizedCredentialDisplays []LocalizedCredentialDisplay `json:"display,omitempty"` - CredentialSubject map[string]*Claim `json:"credentialSubject,omitempty"` - CryptographicBindingMethodsSupported []string `json:"cryptographic_binding_methods_supported,omitempty"` //nolint:lll // Formatter forces these line symbols to line up, and this is a long name - CryptographicSuitesSupported []string `json:"cryptographic_suites_supported,omitempty"` -} - // LocalizedCredentialDisplay represents display data for a credential as a whole for a certain locale. // Display data for specific claims (e.g. first name, date of birth, etc.) are in SupportedCredential.CredentialSubject // (in the parent object above). diff --git a/pkg/openid4ci/issuerinitiatedinteraction_test.go b/pkg/openid4ci/issuerinitiatedinteraction_test.go index c68aa732..f3fb342c 100644 --- a/pkg/openid4ci/issuerinitiatedinteraction_test.go +++ b/pkg/openid4ci/issuerinitiatedinteraction_test.go @@ -1832,7 +1832,8 @@ func TestIssuerInitiatedInteraction_IssuerURI(t *testing.T) { func TestIssuerInitiatedInteraction_VerifyIssuer(t *testing.T) { t.Run("Failed to get issuer metadata", func(t *testing.T) { issuerServerHandler := &mockIssuerServerHandler{ - t: t, + t: t, + issuerMetadata: `{"signed_metadata": "a.b"}`, } server := httptest.NewServer(issuerServerHandler) @@ -1843,7 +1844,7 @@ func TestIssuerInitiatedInteraction_VerifyIssuer(t *testing.T) { serviceURL, err := interaction.VerifyIssuer() require.EqualError(t, err, "METADATA_FETCH_FAILED(OCI1-0004):failed to get issuer metadata: "+ "failed to parse the response from the issuer's OpenID Credential Issuer endpoint as JSON or "+ - "as a JWT: unexpected end of JSON input\nJWT of compacted JWS form is supported only") + "as a JWT: JWT of compacted JWS form is supported only") require.Empty(t, serviceURL) }) t.Run("Resolved DID document has no Linked Domains services specified", func(t *testing.T) { @@ -1892,7 +1893,8 @@ func TestIssuerInitiatedInteraction_VerifyIssuer(t *testing.T) { func TestIssuerInitiatedInteraction_IssuerTrustInfo(t *testing.T) { t.Run("Failed to get issuer metadata", func(t *testing.T) { issuerServerHandler := &mockIssuerServerHandler{ - t: t, + t: t, + issuerMetadata: `{"signed_metadata": "a.b"}`, } server := httptest.NewServer(issuerServerHandler) @@ -1903,7 +1905,7 @@ func TestIssuerInitiatedInteraction_IssuerTrustInfo(t *testing.T) { trustInfo, err := interaction.IssuerTrustInfo() require.EqualError(t, err, "METADATA_FETCH_FAILED(OCI1-0004):failed to get issuer metadata: "+ "failed to parse the response from the issuer's OpenID Credential Issuer endpoint as JSON or "+ - "as a JWT: unexpected end of JSON input\nJWT of compacted JWS form is supported only") + "as a JWT: JWT of compacted JWS form is supported only") require.Nil(t, trustInfo) }) diff --git a/pkg/openid4ci/testdata/sample_signed_issuer_metadata.jwt b/pkg/openid4ci/testdata/sample_signed_issuer_metadata.jwt index c4ad7382..ca2311b8 100644 --- a/pkg/openid4ci/testdata/sample_signed_issuer_metadata.jwt +++ b/pkg/openid4ci/testdata/sample_signed_issuer_metadata.jwt @@ -1 +1,3 @@ -eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDppb246RWlEeXo3NG44aG1OalpWYno3X2RzaGdicVdBZFZfQVhmTUUxVVZLTEtxQTJIUTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKaFpHUXRjSFZpYkdsakxXdGxlWE1pTENKd2RXSnNhV05MWlhseklqcGJleUpwWkNJNklqaE5SekJCVVRsVVIyVnpNMmcyUzI5V1puVlZNVmxOU0RGeFRGbFpUWEpIZVMxWVNrZElOV1pXWW5jaUxDSndkV0pzYVdOTFpYbEtkMnNpT25zaVkzSjJJam9pUldReU5UVXhPU0lzSW10cFpDSTZJamhOUnpCQlVUbFVSMlZ6TTJnMlMyOVdablZWTVZsTlNERnhURmxaVFhKSGVTMVlTa2RJTldaV1luY2lMQ0pyZEhraU9pSlBTMUFpTENKNElqb2lNWFpTYVdoTU9IRmFNRWR6YmprMVoyd3hiR1U0YTJ0YVJtZFBhalpKV1djelRFZExTRUpqUm1OSlp5SjlMQ0p3ZFhKd2IzTmxjeUk2V3lKaGRYUm9aVzUwYVdOaGRHbHZiaUlzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0pkTENKMGVYQmxJam9pU25OdmJsZGxZa3RsZVRJd01qQWlmVjE5TEhzaVlXTjBhVzl1SWpvaVlXUmtMWE5sY25acFkyVnpJaXdpYzJWeWRtbGpaWE1pT2x0N0ltbGtJam9pVEdsdWEyVmtSRzl0WVdsdWN5SXNJbk5sY25acFkyVkZibVJ3YjJsdWRDSTZleUp2Y21sbmFXNXpJanBiSW1oMGRIQnpPaTh2WkdWdGJ5MXBjM04xWlhJdWRISjFjM1JpYkc5akxteHZZMkZzT2pnd056Z3ZJbDE5TENKMGVYQmxJam9pVEdsdWEyVmtSRzl0WVdsdWN5SjlYWDFkTENKMWNHUmhkR1ZEYjIxdGFYUnRaVzUwSWpvaVJXbERaM1JMVUVkelptNTNObFJ6YmxveU5VcHRia1J4YWxsSmVGRjJTblJITFRoSWRIZDVjWFZ2TWpCYWR5SjlMQ0p6ZFdabWFYaEVZWFJoSWpwN0ltUmxiSFJoU0dGemFDSTZJa1ZwUWt4dk5ubFZRMHBKYzNSNWJFVkRTWGh1VW1jdGExQmZaRmhYVTJsSVR5MDRWVTkzWWpNdE1sZEJZMmNpTENKeVpXTnZkbVZ5ZVVOdmJXMXBkRzFsYm5RaU9pSkZhVUZwZWpKVFl6TTNSRk5QWjNoclNscExTVlJVVHpSWlZYbHlSelpZV2xvd2RXWkJNalowZUZwTU1IRlJJbjBzSW5SNWNHVWlPaUpqY21WaGRHVWlmUSM4TUcwQVE5VEdlczNoNktvVmZ1VTFZTUgxcUxZWU1yR3ktWEpHSDVmVmJ3In0.eyJpYXQiOjE3MDE3NzgxODMsImlzcyI6ImRpZDppb246RWlEeXo3NG44aG1OalpWYno3X2RzaGdicVdBZFZfQVhmTUUxVVZLTEtxQTJIUTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKaFpHUXRjSFZpYkdsakxXdGxlWE1pTENKd2RXSnNhV05MWlhseklqcGJleUpwWkNJNklqaE5SekJCVVRsVVIyVnpNMmcyUzI5V1puVlZNVmxOU0RGeFRGbFpUWEpIZVMxWVNrZElOV1pXWW5jaUxDSndkV0pzYVdOTFpYbEtkMnNpT25zaVkzSjJJam9pUldReU5UVXhPU0lzSW10cFpDSTZJamhOUnpCQlVUbFVSMlZ6TTJnMlMyOVdablZWTVZsTlNERnhURmxaVFhKSGVTMVlTa2RJTldaV1luY2lMQ0pyZEhraU9pSlBTMUFpTENKNElqb2lNWFpTYVdoTU9IRmFNRWR6YmprMVoyd3hiR1U0YTJ0YVJtZFBhalpKV1djelRFZExTRUpqUm1OSlp5SjlMQ0p3ZFhKd2IzTmxjeUk2V3lKaGRYUm9aVzUwYVdOaGRHbHZiaUlzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0pkTENKMGVYQmxJam9pU25OdmJsZGxZa3RsZVRJd01qQWlmVjE5TEhzaVlXTjBhVzl1SWpvaVlXUmtMWE5sY25acFkyVnpJaXdpYzJWeWRtbGpaWE1pT2x0N0ltbGtJam9pVEdsdWEyVmtSRzl0WVdsdWN5SXNJbk5sY25acFkyVkZibVJ3YjJsdWRDSTZleUp2Y21sbmFXNXpJanBiSW1oMGRIQnpPaTh2WkdWdGJ5MXBjM04xWlhJdWRISjFjM1JpYkc5akxteHZZMkZzT2pnd056Z3ZJbDE5TENKMGVYQmxJam9pVEdsdWEyVmtSRzl0WVdsdWN5SjlYWDFkTENKMWNHUmhkR1ZEYjIxdGFYUnRaVzUwSWpvaVJXbERaM1JMVUVkelptNTNObFJ6YmxveU5VcHRia1J4YWxsSmVGRjJTblJITFRoSWRIZDVjWFZ2TWpCYWR5SjlMQ0p6ZFdabWFYaEVZWFJoSWpwN0ltUmxiSFJoU0dGemFDSTZJa1ZwUWt4dk5ubFZRMHBKYzNSNWJFVkRTWGh1VW1jdGExQmZaRmhYVTJsSVR5MDRWVTkzWWpNdE1sZEJZMmNpTENKeVpXTnZkbVZ5ZVVOdmJXMXBkRzFsYm5RaU9pSkZhVUZwZWpKVFl6TTNSRk5QWjNoclNscExTVlJVVHpSWlZYbHlSelpZV2xvd2RXWkJNalowZUZwTU1IRlJJbjBzSW5SNWNHVWlPaUpqY21WaGRHVWlmUSIsInN1YiI6ImRpZDppb246RWlEeXo3NG44aG1OalpWYno3X2RzaGdicVdBZFZfQVhmTUUxVVZLTEtxQTJIUTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKaFpHUXRjSFZpYkdsakxXdGxlWE1pTENKd2RXSnNhV05MWlhseklqcGJleUpwWkNJNklqaE5SekJCVVRsVVIyVnpNMmcyUzI5V1puVlZNVmxOU0RGeFRGbFpUWEpIZVMxWVNrZElOV1pXWW5jaUxDSndkV0pzYVdOTFpYbEtkMnNpT25zaVkzSjJJam9pUldReU5UVXhPU0lzSW10cFpDSTZJamhOUnpCQlVUbFVSMlZ6TTJnMlMyOVdablZWTVZsTlNERnhURmxaVFhKSGVTMVlTa2RJTldaV1luY2lMQ0pyZEhraU9pSlBTMUFpTENKNElqb2lNWFpTYVdoTU9IRmFNRWR6YmprMVoyd3hiR1U0YTJ0YVJtZFBhalpKV1djelRFZExTRUpqUm1OSlp5SjlMQ0p3ZFhKd2IzTmxjeUk2V3lKaGRYUm9aVzUwYVdOaGRHbHZiaUlzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0pkTENKMGVYQmxJam9pU25OdmJsZGxZa3RsZVRJd01qQWlmVjE5TEhzaVlXTjBhVzl1SWpvaVlXUmtMWE5sY25acFkyVnpJaXdpYzJWeWRtbGpaWE1pT2x0N0ltbGtJam9pVEdsdWEyVmtSRzl0WVdsdWN5SXNJbk5sY25acFkyVkZibVJ3YjJsdWRDSTZleUp2Y21sbmFXNXpJanBiSW1oMGRIQnpPaTh2WkdWdGJ5MXBjM04xWlhJdWRISjFjM1JpYkc5akxteHZZMkZzT2pnd056Z3ZJbDE5TENKMGVYQmxJam9pVEdsdWEyVmtSRzl0WVdsdWN5SjlYWDFkTENKMWNHUmhkR1ZEYjIxdGFYUnRaVzUwSWpvaVJXbERaM1JMVUVkelptNTNObFJ6YmxveU5VcHRia1J4YWxsSmVGRjJTblJITFRoSWRIZDVjWFZ2TWpCYWR5SjlMQ0p6ZFdabWFYaEVZWFJoSWpwN0ltUmxiSFJoU0dGemFDSTZJa1ZwUWt4dk5ubFZRMHBKYzNSNWJFVkRTWGh1VW1jdGExQmZaRmhYVTJsSVR5MDRWVTkzWWpNdE1sZEJZMmNpTENKeVpXTnZkbVZ5ZVVOdmJXMXBkRzFsYm5RaU9pSkZhVUZwZWpKVFl6TTNSRk5QWjNoclNscExTVlJVVHpSWlZYbHlSelpZV2xvd2RXWkJNalowZUZwTU1IRlJJbjBzSW5SNWNHVWlPaUpqY21WaGRHVWlmUSIsIndlbGxfa25vd25fb3BlbmlkX2lzc3Vlcl9jb25maWd1cmF0aW9uIjp7ImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvb2lkYy9hdXRob3JpemUiLCJjcmVkZW50aWFsX2Fja19lbmRwb2ludCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA3NS9vaWRjL2Fja25vd2xlZGdlbWVudCIsImNyZWRlbnRpYWxfZW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvb2lkYy9jcmVkZW50aWFsIiwiY3JlZGVudGlhbF9pc3N1ZXIiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvaXNzdWVyL2JhbmtfaXNzdWVyL3YxLjAiLCJjcmVkZW50aWFsc19zdXBwb3J0ZWQiOlt7ImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRpc3BsYXlOYW1lIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6IkVtcGxveWVlIn1dLCJvcmRlciI6MCwidmFsdWVfdHlwZSI6InN0cmluZyJ9LCJnaXZlbk5hbWUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiR2l2ZW4gTmFtZSJ9XSwib3JkZXIiOjEsInZhbHVlX3R5cGUiOiJzdHJpbmcifSwiam9iVGl0bGUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiSm9iIFRpdGxlIn1dLCJvcmRlciI6MiwidmFsdWVfdHlwZSI6InN0cmluZyJ9LCJtYWlsIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6Ik1haWwifV0sInZhbHVlX3R5cGUiOiJzdHJpbmcifSwicGhvdG8iOnsiZGlzcGxheSI6W3sibmFtZSI6IlBob3RvIn1dLCJ2YWx1ZV90eXBlIjoiaW1hZ2UifSwicHJlZmVycmVkTGFuZ3VhZ2UiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiUHJlZmVycmVkIExhbmd1YWdlIn1dLCJ2YWx1ZV90eXBlIjoic3RyaW5nIn0sInJlYWxseVNlbnNpdGl2ZUlEIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6IlJlYWxseSBTZW5zaXRpdmUgSUQifV0sIm1hc2siOiJyZWdleCgoLiopKSIsInZhbHVlX3R5cGUiOiJzdHJpbmcifSwic2Vuc2l0aXZlSUQiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiU2Vuc2l0aXZlIElEIn1dLCJtYXNrIjoicmVnZXgoXiguKikuezR9JCkiLCJ2YWx1ZV90eXBlIjoic3RyaW5nIn0sInN1cm5hbWUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiU3VybmFtZSJ9XSwidmFsdWVfdHlwZSI6InN0cmluZyJ9fSwiY3J5cHRvZ3JhcGhpY19iaW5kaW5nX21ldGhvZHNfc3VwcG9ydGVkIjpbImlvbiJdLCJjcnlwdG9ncmFwaGljX3N1aXRlc19zdXBwb3J0ZWQiOlsiRUQyNTUxOSJdLCJkaXNwbGF5IjpbeyJiYWNrZ3JvdW5kX2NvbG9yIjoiIzEyMTA3YyIsImxvY2FsZSI6ImVuLVVTIiwibG9nbyI6eyJhbHRfdGV4dCI6ImEgc3F1YXJlIGxvZ28gb2YgYW4gZW1wbG95ZWUgdmVyaWZpY2F0aW9uIiwidXJsIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9wdWJsaWMvbG9nby5wbmcifSwibmFtZSI6IlZlcmlmaWVkIEVtcGxveWVlIiwidGV4dF9jb2xvciI6IiNGRkZGRkYifV0sImZvcm1hdCI6Imp3dF92Y19qc29uIiwiaWQiOiJWZXJpZmllZEVtcGxveWVlIiwidHlwZXMiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmllZEVtcGxveWVlIl19XSwiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiQmFuayBJc3N1ZXIiLCJ1cmwiOiJodHRwOi8vdmMtcmVzdC1lY2hvLnRydXN0YmxvYy5sb2NhbDo4MDc1In1dLCJncmFudF90eXBlc19zdXBwb3J0ZWQiOlsiYXV0aG9yaXphdGlvbl9jb2RlIl0sInByZS1hdXRob3JpemVkX2dyYW50X2Fub255bW91c19hY2Nlc3Nfc3VwcG9ydGVkIjp0cnVlLCJyZWdpc3RyYXRpb25fZW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvb2lkYy9iYW5rX2lzc3Vlci92MS4wL3JlZ2lzdGVyIiwicmVzcG9uc2VfdHlwZXNfc3VwcG9ydGVkIjpbImNvZGUiXSwic2NvcGVzX3N1cHBvcnRlZCI6WyJvcGVuaWQiLCJwcm9maWxlIl0sInRva2VuX2VuZHBvaW50IjoiaHR0cDovL2xvY2FsaG9zdDo4MDc1L29pZGMvdG9rZW4iLCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjpbIm5vbmUiXX19.Y_0jpMBe0D8l3hMK43pMxq46oUIaDpv3k8z8wr-9CM7MMt0lly8hperTY5f8y8YRyXuGUYXzQUgH0SowobISDw \ No newline at end of file +{ + "signed_metadata": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDppb246RWlEeXo3NG44aG1OalpWYno3X2RzaGdicVdBZFZfQVhmTUUxVVZLTEtxQTJIUTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKaFpHUXRjSFZpYkdsakxXdGxlWE1pTENKd2RXSnNhV05MWlhseklqcGJleUpwWkNJNklqaE5SekJCVVRsVVIyVnpNMmcyUzI5V1puVlZNVmxOU0RGeFRGbFpUWEpIZVMxWVNrZElOV1pXWW5jaUxDSndkV0pzYVdOTFpYbEtkMnNpT25zaVkzSjJJam9pUldReU5UVXhPU0lzSW10cFpDSTZJamhOUnpCQlVUbFVSMlZ6TTJnMlMyOVdablZWTVZsTlNERnhURmxaVFhKSGVTMVlTa2RJTldaV1luY2lMQ0pyZEhraU9pSlBTMUFpTENKNElqb2lNWFpTYVdoTU9IRmFNRWR6YmprMVoyd3hiR1U0YTJ0YVJtZFBhalpKV1djelRFZExTRUpqUm1OSlp5SjlMQ0p3ZFhKd2IzTmxjeUk2V3lKaGRYUm9aVzUwYVdOaGRHbHZiaUlzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0pkTENKMGVYQmxJam9pU25OdmJsZGxZa3RsZVRJd01qQWlmVjE5TEhzaVlXTjBhVzl1SWpvaVlXUmtMWE5sY25acFkyVnpJaXdpYzJWeWRtbGpaWE1pT2x0N0ltbGtJam9pVEdsdWEyVmtSRzl0WVdsdWN5SXNJbk5sY25acFkyVkZibVJ3YjJsdWRDSTZleUp2Y21sbmFXNXpJanBiSW1oMGRIQnpPaTh2WkdWdGJ5MXBjM04xWlhJdWRISjFjM1JpYkc5akxteHZZMkZzT2pnd056Z3ZJbDE5TENKMGVYQmxJam9pVEdsdWEyVmtSRzl0WVdsdWN5SjlYWDFkTENKMWNHUmhkR1ZEYjIxdGFYUnRaVzUwSWpvaVJXbERaM1JMVUVkelptNTNObFJ6YmxveU5VcHRia1J4YWxsSmVGRjJTblJITFRoSWRIZDVjWFZ2TWpCYWR5SjlMQ0p6ZFdabWFYaEVZWFJoSWpwN0ltUmxiSFJoU0dGemFDSTZJa1ZwUWt4dk5ubFZRMHBKYzNSNWJFVkRTWGh1VW1jdGExQmZaRmhYVTJsSVR5MDRWVTkzWWpNdE1sZEJZMmNpTENKeVpXTnZkbVZ5ZVVOdmJXMXBkRzFsYm5RaU9pSkZhVUZwZWpKVFl6TTNSRk5QWjNoclNscExTVlJVVHpSWlZYbHlSelpZV2xvd2RXWkJNalowZUZwTU1IRlJJbjBzSW5SNWNHVWlPaUpqY21WaGRHVWlmUSM4TUcwQVE5VEdlczNoNktvVmZ1VTFZTUgxcUxZWU1yR3ktWEpHSDVmVmJ3In0.eyJpYXQiOjE3MDE3NzgxODMsImlzcyI6ImRpZDppb246RWlEeXo3NG44aG1OalpWYno3X2RzaGdicVdBZFZfQVhmTUUxVVZLTEtxQTJIUTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKaFpHUXRjSFZpYkdsakxXdGxlWE1pTENKd2RXSnNhV05MWlhseklqcGJleUpwWkNJNklqaE5SekJCVVRsVVIyVnpNMmcyUzI5V1puVlZNVmxOU0RGeFRGbFpUWEpIZVMxWVNrZElOV1pXWW5jaUxDSndkV0pzYVdOTFpYbEtkMnNpT25zaVkzSjJJam9pUldReU5UVXhPU0lzSW10cFpDSTZJamhOUnpCQlVUbFVSMlZ6TTJnMlMyOVdablZWTVZsTlNERnhURmxaVFhKSGVTMVlTa2RJTldaV1luY2lMQ0pyZEhraU9pSlBTMUFpTENKNElqb2lNWFpTYVdoTU9IRmFNRWR6YmprMVoyd3hiR1U0YTJ0YVJtZFBhalpKV1djelRFZExTRUpqUm1OSlp5SjlMQ0p3ZFhKd2IzTmxjeUk2V3lKaGRYUm9aVzUwYVdOaGRHbHZiaUlzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0pkTENKMGVYQmxJam9pU25OdmJsZGxZa3RsZVRJd01qQWlmVjE5TEhzaVlXTjBhVzl1SWpvaVlXUmtMWE5sY25acFkyVnpJaXdpYzJWeWRtbGpaWE1pT2x0N0ltbGtJam9pVEdsdWEyVmtSRzl0WVdsdWN5SXNJbk5sY25acFkyVkZibVJ3YjJsdWRDSTZleUp2Y21sbmFXNXpJanBiSW1oMGRIQnpPaTh2WkdWdGJ5MXBjM04xWlhJdWRISjFjM1JpYkc5akxteHZZMkZzT2pnd056Z3ZJbDE5TENKMGVYQmxJam9pVEdsdWEyVmtSRzl0WVdsdWN5SjlYWDFkTENKMWNHUmhkR1ZEYjIxdGFYUnRaVzUwSWpvaVJXbERaM1JMVUVkelptNTNObFJ6YmxveU5VcHRia1J4YWxsSmVGRjJTblJITFRoSWRIZDVjWFZ2TWpCYWR5SjlMQ0p6ZFdabWFYaEVZWFJoSWpwN0ltUmxiSFJoU0dGemFDSTZJa1ZwUWt4dk5ubFZRMHBKYzNSNWJFVkRTWGh1VW1jdGExQmZaRmhYVTJsSVR5MDRWVTkzWWpNdE1sZEJZMmNpTENKeVpXTnZkbVZ5ZVVOdmJXMXBkRzFsYm5RaU9pSkZhVUZwZWpKVFl6TTNSRk5QWjNoclNscExTVlJVVHpSWlZYbHlSelpZV2xvd2RXWkJNalowZUZwTU1IRlJJbjBzSW5SNWNHVWlPaUpqY21WaGRHVWlmUSIsInN1YiI6ImRpZDppb246RWlEeXo3NG44aG1OalpWYno3X2RzaGdicVdBZFZfQVhmTUUxVVZLTEtxQTJIUTpleUprWld4MFlTSTZleUp3WVhSamFHVnpJanBiZXlKaFkzUnBiMjRpT2lKaFpHUXRjSFZpYkdsakxXdGxlWE1pTENKd2RXSnNhV05MWlhseklqcGJleUpwWkNJNklqaE5SekJCVVRsVVIyVnpNMmcyUzI5V1puVlZNVmxOU0RGeFRGbFpUWEpIZVMxWVNrZElOV1pXWW5jaUxDSndkV0pzYVdOTFpYbEtkMnNpT25zaVkzSjJJam9pUldReU5UVXhPU0lzSW10cFpDSTZJamhOUnpCQlVUbFVSMlZ6TTJnMlMyOVdablZWTVZsTlNERnhURmxaVFhKSGVTMVlTa2RJTldaV1luY2lMQ0pyZEhraU9pSlBTMUFpTENKNElqb2lNWFpTYVdoTU9IRmFNRWR6YmprMVoyd3hiR1U0YTJ0YVJtZFBhalpKV1djelRFZExTRUpqUm1OSlp5SjlMQ0p3ZFhKd2IzTmxjeUk2V3lKaGRYUm9aVzUwYVdOaGRHbHZiaUlzSW1GemMyVnlkR2x2YmsxbGRHaHZaQ0pkTENKMGVYQmxJam9pU25OdmJsZGxZa3RsZVRJd01qQWlmVjE5TEhzaVlXTjBhVzl1SWpvaVlXUmtMWE5sY25acFkyVnpJaXdpYzJWeWRtbGpaWE1pT2x0N0ltbGtJam9pVEdsdWEyVmtSRzl0WVdsdWN5SXNJbk5sY25acFkyVkZibVJ3YjJsdWRDSTZleUp2Y21sbmFXNXpJanBiSW1oMGRIQnpPaTh2WkdWdGJ5MXBjM04xWlhJdWRISjFjM1JpYkc5akxteHZZMkZzT2pnd056Z3ZJbDE5TENKMGVYQmxJam9pVEdsdWEyVmtSRzl0WVdsdWN5SjlYWDFkTENKMWNHUmhkR1ZEYjIxdGFYUnRaVzUwSWpvaVJXbERaM1JMVUVkelptNTNObFJ6YmxveU5VcHRia1J4YWxsSmVGRjJTblJITFRoSWRIZDVjWFZ2TWpCYWR5SjlMQ0p6ZFdabWFYaEVZWFJoSWpwN0ltUmxiSFJoU0dGemFDSTZJa1ZwUWt4dk5ubFZRMHBKYzNSNWJFVkRTWGh1VW1jdGExQmZaRmhYVTJsSVR5MDRWVTkzWWpNdE1sZEJZMmNpTENKeVpXTnZkbVZ5ZVVOdmJXMXBkRzFsYm5RaU9pSkZhVUZwZWpKVFl6TTNSRk5QWjNoclNscExTVlJVVHpSWlZYbHlSelpZV2xvd2RXWkJNalowZUZwTU1IRlJJbjBzSW5SNWNHVWlPaUpqY21WaGRHVWlmUSIsIndlbGxfa25vd25fb3BlbmlkX2lzc3Vlcl9jb25maWd1cmF0aW9uIjp7ImF1dGhvcml6YXRpb25fZW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvb2lkYy9hdXRob3JpemUiLCJjcmVkZW50aWFsX2Fja19lbmRwb2ludCI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA3NS9vaWRjL2Fja25vd2xlZGdlbWVudCIsImNyZWRlbnRpYWxfZW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvb2lkYy9jcmVkZW50aWFsIiwiY3JlZGVudGlhbF9pc3N1ZXIiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvaXNzdWVyL2JhbmtfaXNzdWVyL3YxLjAiLCJjcmVkZW50aWFsc19zdXBwb3J0ZWQiOlt7ImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImRpc3BsYXlOYW1lIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6IkVtcGxveWVlIn1dLCJvcmRlciI6MCwidmFsdWVfdHlwZSI6InN0cmluZyJ9LCJnaXZlbk5hbWUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiR2l2ZW4gTmFtZSJ9XSwib3JkZXIiOjEsInZhbHVlX3R5cGUiOiJzdHJpbmcifSwiam9iVGl0bGUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiSm9iIFRpdGxlIn1dLCJvcmRlciI6MiwidmFsdWVfdHlwZSI6InN0cmluZyJ9LCJtYWlsIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6Ik1haWwifV0sInZhbHVlX3R5cGUiOiJzdHJpbmcifSwicGhvdG8iOnsiZGlzcGxheSI6W3sibmFtZSI6IlBob3RvIn1dLCJ2YWx1ZV90eXBlIjoiaW1hZ2UifSwicHJlZmVycmVkTGFuZ3VhZ2UiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiUHJlZmVycmVkIExhbmd1YWdlIn1dLCJ2YWx1ZV90eXBlIjoic3RyaW5nIn0sInJlYWxseVNlbnNpdGl2ZUlEIjp7ImRpc3BsYXkiOlt7ImxvY2FsZSI6ImVuLVVTIiwibmFtZSI6IlJlYWxseSBTZW5zaXRpdmUgSUQifV0sIm1hc2siOiJyZWdleCgoLiopKSIsInZhbHVlX3R5cGUiOiJzdHJpbmcifSwic2Vuc2l0aXZlSUQiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiU2Vuc2l0aXZlIElEIn1dLCJtYXNrIjoicmVnZXgoXiguKikuezR9JCkiLCJ2YWx1ZV90eXBlIjoic3RyaW5nIn0sInN1cm5hbWUiOnsiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiU3VybmFtZSJ9XSwidmFsdWVfdHlwZSI6InN0cmluZyJ9fSwiY3J5cHRvZ3JhcGhpY19iaW5kaW5nX21ldGhvZHNfc3VwcG9ydGVkIjpbImlvbiJdLCJjcnlwdG9ncmFwaGljX3N1aXRlc19zdXBwb3J0ZWQiOlsiRUQyNTUxOSJdLCJkaXNwbGF5IjpbeyJiYWNrZ3JvdW5kX2NvbG9yIjoiIzEyMTA3YyIsImxvY2FsZSI6ImVuLVVTIiwibG9nbyI6eyJhbHRfdGV4dCI6ImEgc3F1YXJlIGxvZ28gb2YgYW4gZW1wbG95ZWUgdmVyaWZpY2F0aW9uIiwidXJsIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9wdWJsaWMvbG9nby5wbmcifSwibmFtZSI6IlZlcmlmaWVkIEVtcGxveWVlIiwidGV4dF9jb2xvciI6IiNGRkZGRkYifV0sImZvcm1hdCI6Imp3dF92Y19qc29uIiwiaWQiOiJWZXJpZmllZEVtcGxveWVlIiwidHlwZXMiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJWZXJpZmllZEVtcGxveWVlIl19XSwiZGlzcGxheSI6W3sibG9jYWxlIjoiZW4tVVMiLCJuYW1lIjoiQmFuayBJc3N1ZXIiLCJ1cmwiOiJodHRwOi8vdmMtcmVzdC1lY2hvLnRydXN0YmxvYy5sb2NhbDo4MDc1In1dLCJncmFudF90eXBlc19zdXBwb3J0ZWQiOlsiYXV0aG9yaXphdGlvbl9jb2RlIl0sInByZS1hdXRob3JpemVkX2dyYW50X2Fub255bW91c19hY2Nlc3Nfc3VwcG9ydGVkIjp0cnVlLCJyZWdpc3RyYXRpb25fZW5kcG9pbnQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzUvb2lkYy9iYW5rX2lzc3Vlci92MS4wL3JlZ2lzdGVyIiwicmVzcG9uc2VfdHlwZXNfc3VwcG9ydGVkIjpbImNvZGUiXSwic2NvcGVzX3N1cHBvcnRlZCI6WyJvcGVuaWQiLCJwcm9maWxlIl0sInRva2VuX2VuZHBvaW50IjoiaHR0cDovL2xvY2FsaG9zdDo4MDc1L29pZGMvdG9rZW4iLCJ0b2tlbl9lbmRwb2ludF9hdXRoX21ldGhvZHNfc3VwcG9ydGVkIjpbIm5vbmUiXX19.Y_0jpMBe0D8l3hMK43pMxq46oUIaDpv3k8z8wr-9CM7MMt0lly8hperTY5f8y8YRyXuGUYXzQUgH0SowobISDw" +} \ No newline at end of file diff --git a/pkg/openid4ci/walletinitiatedinteraction.go b/pkg/openid4ci/walletinitiatedinteraction.go index c18cd7e7..018ba8aa 100644 --- a/pkg/openid4ci/walletinitiatedinteraction.go +++ b/pkg/openid4ci/walletinitiatedinteraction.go @@ -71,13 +71,14 @@ func (i *WalletInitiatedInteraction) SupportedCredentials() ([]SupportedCredenti return nil, err } - supportedCredentials := make([]SupportedCredential, len(i.interaction.issuerMetadata.CredentialsSupported)) + credentialConf := i.interaction.issuerMetadata.CredentialConfigurationsSupported + supportedCredentials := make([]SupportedCredential, 0, len(credentialConf)) - for j := 0; j < len(i.interaction.issuerMetadata.CredentialsSupported); j++ { - supportedCredentials[j] = SupportedCredential{ - Format: i.interaction.issuerMetadata.CredentialsSupported[j].Format, - Types: i.interaction.issuerMetadata.CredentialsSupported[j].Types, - } + for _, credentialConfiguration := range credentialConf { + supportedCredentials = append(supportedCredentials, SupportedCredential{ + Format: credentialConfiguration.Format, + Types: credentialConfiguration.CredentialDefinition.Type, + }) } return supportedCredentials, nil diff --git a/scripts/build_vcs.sh b/scripts/build_vcs.sh new file mode 100755 index 00000000..b019ee1f --- /dev/null +++ b/scripts/build_vcs.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# +# Copyright Avast Software. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -e + +echo "Copying vcs..." +pwd=$(pwd) +rm -rf ./.build/vcs +git clone -b main https://github.com/trustbloc/vcs ./.build/vcs +cd ./.build/vcs || exit + +git checkout ${VCS_COMMIT} + +cp -rf ../../test/integration/fixtures ./test/bdd/ + +make generate + +cd cmd/vc-rest || exit + +go mod tidy + +cd $pwd || exit diff --git a/test/integration/fixtures/.env b/test/integration/fixtures/.env index 6f69b80e..2b176b6c 100644 --- a/test/integration/fixtures/.env +++ b/test/integration/fixtures/.env @@ -6,7 +6,7 @@ # vc services VC_REST_IMAGE=ghcr.io/trustbloc-cicd/vc-server -VC_REST_IMAGE_TAG=v1.5.1-snapshot-aad1d14 +VC_REST_IMAGE_TAG=latest # Remote JSON-LD context provider CONTEXT_PROVIDER_URL=https://file-server.trustbloc.local:10096/ld-contexts.json diff --git a/test/integration/fixtures/profile/profiles.json b/test/integration/fixtures/profile/profiles.json index c57e8363..85926a35 100644 --- a/test/integration/fixtures/profile/profiles.json +++ b/test/integration/fixtures/profile/profiles.json @@ -53,121 +53,122 @@ } ], "credentialMetadata": { - "credentials_supported": [ - { - "id": "VerifiedEmployee", + "credential_configurations_supported": { + "VerifiedEmployee_jwt_vc_json_v1": { "format": "jwt_vc_json", - "types":[ - "VerifiableCredential", - "VerifiedEmployee" - ], - "cryptographic_binding_methods_supported":[ + "credential_definition": { + "type": [ + "VerifiableCredential", + "VerifiedEmployee" + ], + "credentialSubject": { + "displayName": { + "display": [ + { + "locale": "en-US", + "name": "Employee" + } + ], + "value_type": "string", + "order": 0 + }, + "givenName": { + "display": [ + { + "locale": "en-US", + "name": "Given Name" + } + ], + "value_type": "string", + "order": 1 + }, + "jobTitle": { + "display": [ + { + "locale": "en-US", + "name": "Job Title" + } + ], + "value_type": "string", + "order": 2 + }, + "mail": { + "display": [ + { + "locale": "en-US", + "name": "Mail" + } + ], + "value_type": "string" + }, + "photo": { + "display": [ + { + "name": "Photo" + } + ], + "value_type": "image" + }, + "preferredLanguage": { + "display": [ + { + "locale": "en-US", + "name": "Preferred Language" + } + ], + "value_type": "string" + }, + "surname": { + "display": [ + { + "locale": "en-US", + "name": "Surname" + } + ], + "value_type": "string" + }, + "sensitiveID": { + "display": [ + { + "name": "Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex(^(.*).{4}$)" + }, + "reallySensitiveID": { + "display": [ + { + "name": "Really Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex((.*))" + } + } + }, + "cryptographic_binding_methods_supported": [ "did" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "Ed25519Signature2018" ], - "credentialSubject":{ - "displayName":{ - "display":[ - { - "locale":"en-US", - "name":"Employee" - } - ], - "value_type":"string", - "order": 0 - }, - "givenName":{ - "display":[ - { - "locale":"en-US", - "name":"Given Name" - } - ], - "value_type":"string", - "order": 1 - }, - "jobTitle":{ - "display":[ - { - "locale":"en-US", - "name":"Job Title" - } - ], - "value_type":"string", - "order": 2 - }, - "mail":{ - "display":[ - { - "locale":"en-US", - "name":"Mail" - } - ], - "value_type":"string" - }, - "photo":{ - "display":[ - { - "name":"Photo" - } - ], - "value_type":"image" - }, - "preferredLanguage":{ - "display":[ - { - "locale":"en-US", - "name":"Preferred Language" - } - ], - "value_type":"string" - }, - "surname":{ - "display":[ - { - "locale":"en-US", - "name":"Surname" - } - ], - "value_type":"string" - }, - "sensitiveID":{ - "display":[ - { - "name":"Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex(^(.*).{4}$)" - }, - "reallySensitiveID":{ - "display":[ - { - "name":"Really Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex((.*))" - } - }, - "display":[ + "display": [ { - "background_color":"#12107c", - "locale":"en-US", - "logo":{ - "alt_text":"a square logo of an employee verification", - "url":"https://example.com/public/logo.png" + "background_color": "#12107c", + "locale": "en-US", + "logo": { + "alt_text": "a square logo of an employee verification", + "url": "https://example.com/public/logo.png" }, - "name":"Verified Employee", - "text_color":"#FFFFFF" + "name": "Verified Employee", + "text_color": "#FFFFFF" } ] } - ] + } } }, "createDID": true @@ -221,18 +222,138 @@ } ], "credentialMetadata": { - "credentials_supported": [ - { - "id": "DriversLicense", + "credential_configurations_supported": { + "DriversLicense_jwt_vc_json_v1": { "format": "jwt_vc_json", - "types":[ - "VerifiableCredential", - "DriversLicense" - ], - "cryptographic_binding_methods_supported":[ + "credential_definition": { + "type": [ + "VerifiableCredential", + "DriversLicense" + ], + "credentialSubject": { + "birthdate": { + "display": [ + { + "name": "Birth Date", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "document_number": { + "display": [ + { + "name": "Document Number", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "driving_privileges": { + "display": [ + { + "name": "Driving Privileges", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "expiry_date": { + "display": [ + { + "name": "Expiry Date", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "family_name": { + "display": [ + { + "name": "Family Name", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "given_name": { + "display": [ + { + "name": "Given Name", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "issue_date": { + "display": [ + { + "name": "Issue Date", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "issuing_authority": { + "display": [ + { + "name": "Issuing Authority", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "issuing_country": { + "display": [ + { + "name": "Issuing Country", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "resident_address": { + "display": [ + { + "name": "Resident Address", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "resident_city": { + "display": [ + { + "name": "Resident City", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "resident_postal_code": { + "display": [ + { + "name": "Resident Postal Code", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "resident_province": { + "display": [ + { + "name": "Resident Province", + "locale": "en-US" + } + ], + "value_type": "string" + } + } + }, + "cryptographic_binding_methods_supported": [ "did" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "Ed25519Signature2018" ], "display": [ @@ -246,128 +367,9 @@ "background_color": "#12107c", "text_color": "#FFFFFF" } - ], - "credentialSubject": { - "birthdate": { - "display": [ - { - "name": "Birth Date", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "document_number": { - "display": [ - { - "name": "Document Number", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "driving_privileges": { - "display": [ - { - "name": "Driving Privileges", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "expiry_date": { - "display": [ - { - "name": "Expiry Date", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "family_name": { - "display": [ - { - "name": "Family Name", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "given_name": { - "display": [ - { - "name": "Given Name", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "issue_date": { - "display": [ - { - "name": "Issue Date", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "issuing_authority": { - "display": [ - { - "name": "Issuing Authority", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "issuing_country": { - "display": [ - { - "name": "Issuing Country", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "resident_address": { - "display": [ - { - "name": "Resident Address", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "resident_city": { - "display": [ - { - "name": "Resident City", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "resident_postal_code": { - "display": [ - { - "name": "Resident Postal Code", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "resident_province": { - "display": [ - { - "name": "Resident Province", - "locale": "en-US" - } - ], - "value_type":"string" - } - } + ] } - ] + } } }, "createDID": true @@ -425,18 +427,106 @@ } ], "credentialMetadata": { - "credentials_supported": [ - { - "id": "VerifiedEmployee", + "credential_configurations_supported": { + "VerifiedEmployee_jwt_vc_json_v1": { "format": "jwt_vc_json", - "types":[ - "VerifiableCredential", - "VerifiedEmployee" - ], - "cryptographic_binding_methods_supported":[ + "credential_definition": { + "type": [ + "VerifiableCredential", + "VerifiedEmployee" + ], + "credentialSubject": { + "displayName": { + "display": [ + { + "name": "Employee", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 0 + }, + "givenName": { + "display": [ + { + "name": "Given Name", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 1 + }, + "jobTitle": { + "display": [ + { + "name": "Job Title", + "locale": "en-US" + } + ], + "value_type": "string", + "order": 2 + }, + "surname": { + "display": [ + { + "name": "Surname", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "preferredLanguage": { + "display": [ + { + "name": "Preferred Language", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "mail": { + "display": [ + { + "name": "Mail", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "photo": { + "display": [ + { + "name": "Photo" + } + ], + "value_type": "image" + }, + "sensitiveID": { + "display": [ + { + "name": "Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex(^(.*).{4}$)" + }, + "reallySensitiveID": { + "display": [ + { + "name": "Really Sensitive ID", + "locale": "en-US" + } + ], + "value_type": "string", + "mask": "regex((.*))" + } + } + }, + "cryptographic_binding_methods_supported": [ "did" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "Ed25519Signature2018" ], "display": [ @@ -450,96 +540,9 @@ "background_color": "#12107c", "text_color": "#FFFFFF" } - ], - "credentialSubject": { - "displayName": { - "display": [ - { - "name": "Employee", - "locale": "en-US" - } - ], - "value_type":"string", - "order":0 - }, - "givenName": { - "display": [ - { - "name": "Given Name", - "locale": "en-US" - } - ], - "value_type":"string", - "order":1 - }, - "jobTitle": { - "display": [ - { - "name": "Job Title", - "locale": "en-US" - } - ], - "value_type":"string", - "order":2 - }, - "surname": { - "display": [ - { - "name": "Surname", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "preferredLanguage": { - "display": [ - { - "name": "Preferred Language", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "mail": { - "display": [ - { - "name": "Mail", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "photo": { - "display": [ - { - "name": "Photo" - } - ], - "value_type":"image" - }, - "sensitiveID":{ - "display":[ - { - "name":"Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex(^(.*).{4}$)" - }, - "reallySensitiveID":{ - "display":[ - { - "name":"Really Sensitive ID", - "locale":"en-US" - } - ], - "value_type":"string", - "mask":"regex((.*))" - } - } + ] } - ] + } } }, "createDID": true, @@ -598,18 +601,65 @@ } ], "credentialMetadata": { - "credentials_supported": [ - { - "id": "UniversityDegreeCredential", + "credential_configurations_supported": { + "UniversityDegreeCredential_ldp_vc_v1": { "format": "ldp_vc", - "types":[ - "VerifiableCredential", - "UniversityDegreeCredential" - ], - "cryptographic_binding_methods_supported":[ + "credential_definition": { + "type": [ + "VerifiableCredential", + "UniversityDegreeCredential" + ], + "credentialSubject": { + "familyName": { + "display": [ + { + "name": "Family Name", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "givenName": { + "display": [ + { + "name": "Given Name", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "degree": { + "display": [ + { + "name": "Degree", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "photo": { + "display": [ + { + "name": "Photo" + } + ], + "value_type": "image" + }, + "degreeSchool": { + "display": [ + { + "name": "Degree School", + "locale": "en-US" + } + ], + "value_type": "string" + } + } + }, + "cryptographic_binding_methods_supported": [ "did" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "Ed25519Signature2018" ], "display": [ @@ -623,55 +673,9 @@ "background_color": "#12107c", "text_color": "#FFFFFF" } - ], - "credentialSubject": { - "familyName": { - "display": [ - { - "name": "Family Name", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "givenName": { - "display": [ - { - "name": "Given Name", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "degree": { - "display": [ - { - "name": "Degree", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "photo":{ - "display":[ - { - "name":"Photo" - } - ], - "value_type":"image" - }, - "degreeSchool": { - "display": [ - { - "name": "Degree School", - "locale": "en-US" - } - ], - "value_type":"string" - } - } + ] } - ] + } } }, "createDID": true @@ -729,18 +733,65 @@ } ], "credentialMetadata": { - "credentials_supported": [ - { - "id": "UniversityDegreeCredential", + "credential_configurations_supported": { + "UniversityDegreeCredential_ldp_vc_v1": { "format": "ldp_vc", - "types":[ - "VerifiableCredential", - "UniversityDegreeCredential" - ], - "cryptographic_binding_methods_supported":[ + "credential_definition": { + "type": [ + "VerifiableCredential", + "UniversityDegreeCredential" + ], + "credentialSubject": { + "familyName": { + "display": [ + { + "name": "Family Name", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "givenName": { + "display": [ + { + "name": "Given Name", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "photo": { + "display": [ + { + "name": "Photo" + } + ], + "value_type": "image" + }, + "degree": { + "display": [ + { + "name": "Degree", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "degreeSchool": { + "display": [ + { + "name": "Degree School", + "locale": "en-US" + } + ], + "value_type": "string" + } + } + }, + "cryptographic_binding_methods_supported": [ "did" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "Ed25519Signature2018" ], "display": [ @@ -754,55 +805,9 @@ "background_color": "#12107c", "text_color": "#FFFFFF" } - ], - "credentialSubject": { - "familyName": { - "display": [ - { - "name": "Family Name", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "givenName": { - "display": [ - { - "name": "Given Name", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "photo":{ - "display":[ - { - "name":"Photo" - } - ], - "value_type":"image" - }, - "degree": { - "display": [ - { - "name": "Degree", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "degreeSchool": { - "display": [ - { - "name": "Degree School", - "locale": "en-US" - } - ], - "value_type":"string" - } - } + ] } - ] + } } }, "createDID": true @@ -856,18 +861,83 @@ } ], "credentialMetadata": { - "credentials_supported": [ - { - "id": "VerifiedEmployee", + "credential_configurations_supported": { + "VerifiedEmployee_jwt_vc_json_v1": { "format": "jwt_vc_json", - "types":[ - "VerifiableCredential", - "VerifiedEmployee" - ], - "cryptographic_binding_methods_supported":[ + "credential_definition": { + "type": [ + "VerifiableCredential", + "VerifiedEmployee" + ], + "credentialSubject": { + "displayName": { + "display": [ + { + "name": "Employee", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "givenName": { + "display": [ + { + "name": "Given Name", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "jobTitle": { + "display": [ + { + "name": "Job Title", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "surname": { + "display": [ + { + "name": "Surname", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "preferredLanguage": { + "display": [ + { + "name": "Preferred Language", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "mail": { + "display": [ + { + "name": "Mail", + "locale": "en-US" + } + ], + "value_type": "string" + }, + "photo": { + "display": [ + { + "name": "Photo" + } + ], + "value_type": "image" + } + } + }, + "cryptographic_binding_methods_supported": [ "did" ], - "cryptographic_suites_supported":[ + "cryptographic_suites_supported": [ "Ed25519Signature2018" ], "display": [ @@ -881,73 +951,9 @@ "background_color": "#12107c", "text_color": "#FFFFFF" } - ], - "credentialSubject": { - "displayName": { - "display": [ - { - "name": "Employee", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "givenName": { - "display": [ - { - "name": "Given Name", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "jobTitle": { - "display": [ - { - "name": "Job Title", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "surname": { - "display": [ - { - "name": "Surname", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "preferredLanguage": { - "display": [ - { - "name": "Preferred Language", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "mail": { - "display": [ - { - "name": "Mail", - "locale": "en-US" - } - ], - "value_type":"string" - }, - "photo": { - "display": [ - { - "name": "Photo" - } - ], - "value_type":"image" - } - } + ] } - ] + } } }, "createDID": true @@ -1103,7 +1109,7 @@ "name": "Degree", "purpose": "We can only hire with university degree.", "constraints": { - "limit_disclosure":"required", + "limit_disclosure": "required", "fields": [ { "path": [ @@ -1203,7 +1209,7 @@ "path": [ "$.credentialSubject.jobTitle", "$.vc.credentialSubject.jobTitle" - ], + ], "purpose": "We can only hire software developers.", "filter": { "type": "string", @@ -1383,29 +1389,29 @@ } ], "constraints": { - "limit_disclosure":"required", - "fields":[ + "limit_disclosure": "required", + "fields": [ { "id": "issuer-name", - "path":[ + "path": [ "$.issuer.name", "$.vc.issuer.name" ], - "purpose":"The claim must be from one of the specified issuers", - "filter":{ - "type":"string", - "pattern":"Bank Issuer" + "purpose": "The claim must be from one of the specified issuers", + "filter": { + "type": "string", + "pattern": "Bank Issuer" } }, { "id": "job-title", - "path":[ + "path": [ "$.credentialSubject.jobTitle", "$.vc.credentialSubject.jobTitle", "$.jobTitle" ], - "filter":{ - "type":"string" + "filter": { + "type": "string" } } ]