From 0971f6a66bac16dc896ef330b243d8e9c8d23eab Mon Sep 17 00:00:00 2001 From: Stefan Wiedemann Date: Fri, 28 Apr 2023 15:16:35 +0200 Subject: [PATCH] make it optional --- openapi/api_api.go | 2 +- verifier/verifiable_credential.go | 23 ++++++++-- verifier/verifiable_credential_test.go | 62 ++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/openapi/api_api.go b/openapi/api_api.go index 14bf692f..754bb404 100644 --- a/openapi/api_api.go +++ b/openapi/api_api.go @@ -166,7 +166,7 @@ func handleAuthenticationResponse(c *gin.Context, state string, vpToken string) sameDeviceResponse, err := getApiVerifier().AuthenticationResponse(state, rawCredentials, holder) if err != nil { - logging.Log().Warnf("Was not able to get fullfil the authentication response. Err: %v", err) + logging.Log().Warnf("Was not able to fullfil the authentication response. Err: %v", err) c.AbortWithStatusJSON(400, ErrorMessage{Summary: err.Error()}) return } diff --git a/verifier/verifiable_credential.go b/verifier/verifiable_credential.go index 72801757..df27c2ad 100644 --- a/verifier/verifiable_credential.go +++ b/verifier/verifiable_credential.go @@ -1,10 +1,12 @@ package verifier import ( + "errors" "reflect" logging "github.com/fiware/VCVerifier/logging" "github.com/mitchellh/mapstructure" + "golang.org/x/exp/slices" ) // Subset of the structure of a Verifiable Credential @@ -27,6 +29,10 @@ type CredentialSubject struct { SubjectType string `mapstructure:"type"` } +func optionalFields() []string { + return []string{"credentialSubject.id", "credentialSubject.type"} +} + func (vc VerifiableCredential) GetCredentialType() string { return vc.CredentialSubject.SubjectType } @@ -41,6 +47,7 @@ func (vc VerifiableCredential) GetIssuer() string { func MapVerifiableCredential(raw map[string]interface{}) (VerifiableCredential, error) { var data MappableVerifiableCredential + var metaData mapstructure.Metadata credentialSubjectArrayDecoder := func(from, to reflect.Type, data interface{}) (interface{}, error) { if to != reflect.TypeOf((*CredentialSubject)(nil)).Elem() { @@ -50,18 +57,19 @@ func MapVerifiableCredential(raw map[string]interface{}) (VerifiableCredential, return data, nil } vcArray := data.([]interface{}) - if len(vcArray) > 0{ + if len(vcArray) > 0 { logging.Log().Warn("Found more than one credential subject. Will only use/validate first one.") return vcArray[0], nil - }else{ - return []interface{}{},nil + } else { + return []interface{}{}, nil } } config := &mapstructure.DecoderConfig{ ErrorUnused: false, Result: &data, - ErrorUnset: true, + Metadata: &metaData, + ErrorUnset: false, IgnoreUntaggedFields: true, DecodeHook: credentialSubjectArrayDecoder, } @@ -72,5 +80,12 @@ func MapVerifiableCredential(raw map[string]interface{}) (VerifiableCredential, if err := decoder.Decode(raw); err != nil { return VerifiableCredential{}, err } + + for _, unsetField := range metaData.Unset { + if !slices.Contains(optionalFields(), unsetField) { + return VerifiableCredential{}, errors.New("unset_field") + } + } + return VerifiableCredential{data, raw}, nil } diff --git a/verifier/verifiable_credential_test.go b/verifier/verifiable_credential_test.go index 6ea6b131..0ca2e944 100644 --- a/verifier/verifiable_credential_test.go +++ b/verifier/verifiable_credential_test.go @@ -27,6 +27,40 @@ var exampleCredential = map[string]interface{}{ "type": "gx:compliance", }, } + +var exampleEmptySubjectCredential = map[string]interface{}{ + "@context": []string{ + "https://www.w3.org/2018/credentials/v1", + "https://happypets.fiware.io/2022/credentials/employee/v1", + }, + "id": "https://happypets.fiware.io/credential/25159389-8dd17b796ac0", + "type": []string{ + "VerifiableCredential", + "CustomerCredential", + }, + "issuer": "did:key:verifier", + "issuanceDate": "2022-11-23T15:23:13Z", + "validFrom": "2022-11-23T15:23:13Z", + "expirationDate": "2032-11-23T15:23:13Z", + "credentialSubject": map[string]interface{}{}, +} + +var exampleNoIdCredential = map[string]interface{}{ + "@context": []string{ + "https://www.w3.org/2018/credentials/v1", + "https://happypets.fiware.io/2022/credentials/employee/v1", + }, + "type": []string{ + "VerifiableCredential", + "CustomerCredential", + }, + "issuer": "did:key:verifier", + "issuanceDate": "2022-11-23T15:23:13Z", + "validFrom": "2022-11-23T15:23:13Z", + "expirationDate": "2032-11-23T15:23:13Z", + "credentialSubject": map[string]interface{}{}, +} + var exampleCredentialArraySubject = map[string]interface{}{ "@context": []string{ "https://www.w3.org/2018/credentials/v1", @@ -84,7 +118,6 @@ func getComplianceVCFromJson() map[string]interface{} { return x } - func TestActualComplianceCredential(t *testing.T) { _, err := MapVerifiableCredential(getComplianceVCFromJson()) @@ -105,7 +138,7 @@ func TestMapVerifiableCredential(t *testing.T) { wantErr bool }{ { - "ValidCertificate", + "ValidCredential", args{exampleCredential}, VerifiableCredential{ MappableVerifiableCredential{ @@ -124,6 +157,23 @@ func TestMapVerifiableCredential(t *testing.T) { }, false, }, + { + "ValidCredentialWithEmptySubject", + args{exampleEmptySubjectCredential}, + VerifiableCredential{ + MappableVerifiableCredential{ + Id: "https://happypets.fiware.io/credential/25159389-8dd17b796ac0", + Types: []string{ + "VerifiableCredential", + "CustomerCredential", + }, + Issuer: "did:key:verifier", + CredentialSubject: CredentialSubject{}, + }, + exampleEmptySubjectCredential, + }, + false, + }, { "ValidCertificateArraySubject", args{exampleCredentialArraySubject}, @@ -145,11 +195,17 @@ func TestMapVerifiableCredential(t *testing.T) { false, }, { - "InvalidCertificate", + "InvalidCredential", args{map[string]interface{}{"someThing": "else"}}, VerifiableCredential{}, true, }, + { + "NoIdCredential", + args{exampleNoIdCredential}, + VerifiableCredential{}, + true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {