github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/presexch/match_submission_requirements_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package presexch_test 8 9 import ( 10 "crypto/sha256" 11 _ "embed" 12 "encoding/json" 13 "fmt" 14 "testing" 15 "time" 16 17 "github.com/google/uuid" 18 "github.com/stretchr/testify/require" 19 20 "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub" 21 "github.com/hyperledger/aries-framework-go/pkg/doc/presexch" 22 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" 23 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite" 24 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignature2020" 25 "github.com/hyperledger/aries-framework-go/pkg/doc/util" 26 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 27 ) 28 29 var ( 30 //go:embed testdata/presentation_definition.json 31 presentationDefinition []byte 32 33 //go:embed testdata/submission_requirements_pd.json 34 submissionRequirementsPD []byte 35 36 //go:embed testdata/nested_submission_requirements_pd.json 37 nestedSubmissionRequirementsPD []byte 38 39 //go:embed testdata/university_degree.jwt 40 universityDegreeVC []byte 41 42 //go:embed testdata/permanent_resident_card.jwt 43 permanentResidentCardVC []byte 44 45 //go:embed testdata/drivers_license.jwt 46 driverLicenseVC []byte 47 48 //go:embed testdata/drivers_license2.jwt 49 driverLicenseVC2 []byte 50 51 //go:embed testdata/verified_employee.jwt 52 verifiedEmployeeVC []byte 53 ) 54 55 const ( 56 driversLicenseVCType = "DriversLicense" 57 ) 58 59 func TestInstance_GetSubmissionRequirements(t *testing.T) { 60 docLoader := createTestJSONLDDocumentLoader(t) 61 62 contents := [][]byte{ 63 universityDegreeVC, 64 permanentResidentCardVC, 65 driverLicenseVC, 66 driverLicenseVC2, 67 verifiedEmployeeVC, 68 } 69 70 var credentials []*verifiable.Credential 71 72 for _, credContent := range contents { 73 cred, credErr := verifiable.ParseCredential(credContent, verifiable.WithDisabledProofCheck(), 74 verifiable.WithJSONLDDocumentLoader(docLoader)) 75 require.NoError(t, credErr) 76 77 credentials = append(credentials, cred) 78 } 79 80 t.Run("Success", func(t *testing.T) { 81 pdQuery := &presexch.PresentationDefinition{} 82 err := json.Unmarshal(presentationDefinition, pdQuery) 83 require.NoError(t, err) 84 85 requirements, err := pdQuery.MatchSubmissionRequirement( 86 credentials, 87 docLoader, 88 ) 89 90 require.NoError(t, err) 91 require.Len(t, requirements, 1) 92 93 require.Len(t, requirements[0].Descriptors, 3) 94 95 for _, desc := range requirements[0].Descriptors { 96 if desc.ID == driversLicenseVCType { 97 require.Len(t, desc.MatchedVCs, 2) 98 } 99 } 100 }) 101 102 t.Run("Success with submission requirements", func(t *testing.T) { 103 pdQuery := &presexch.PresentationDefinition{} 104 err := json.Unmarshal(submissionRequirementsPD, pdQuery) 105 require.NoError(t, err) 106 107 requirements, err := pdQuery.MatchSubmissionRequirement( 108 credentials, 109 docLoader, 110 ) 111 112 require.NoError(t, err) 113 require.Len(t, requirements, 1) 114 115 require.Len(t, requirements[0].Descriptors, 3) 116 117 for _, desc := range requirements[0].Descriptors { 118 if desc.ID == driversLicenseVCType { 119 require.Len(t, desc.MatchedVCs, 2) 120 } 121 } 122 }) 123 124 t.Run("Success with nested submission requirements", func(t *testing.T) { 125 pdQuery := &presexch.PresentationDefinition{} 126 err := json.Unmarshal(nestedSubmissionRequirementsPD, pdQuery) 127 require.NoError(t, err) 128 129 requirements, err := pdQuery.MatchSubmissionRequirement( 130 credentials, 131 docLoader, 132 ) 133 134 require.NoError(t, err) 135 require.Len(t, requirements, 1) 136 137 require.Len(t, requirements[0].Descriptors, 0) 138 require.Len(t, requirements[0].Nested, 2) 139 140 for _, req := range requirements[0].Nested { 141 if req.Name == "VerifiedEmployee or Degree" { 142 require.Len(t, req.Descriptors, 2) 143 } 144 145 if req.Name == driversLicenseVCType { 146 require.Len(t, req.Descriptors, 1) 147 require.Len(t, req.Descriptors[0].MatchedVCs, 2) 148 } 149 } 150 }) 151 152 t.Run("Limit disclosure BBS+", func(t *testing.T) { 153 required := presexch.Required 154 155 pd := &presexch.PresentationDefinition{ 156 ID: uuid.New().String(), 157 InputDescriptors: []*presexch.InputDescriptor{{ 158 Schema: []*presexch.Schema{{ 159 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 160 }}, 161 ID: uuid.New().String(), 162 Constraints: &presexch.Constraints{ 163 LimitDisclosure: &required, 164 Fields: []*presexch.Field{{ 165 Path: []string{"$.credentialSubject.degree.degreeSchool"}, 166 Filter: &presexch.Filter{Type: &strFilterType}, 167 }}, 168 }, 169 }}, 170 } 171 172 vc := &verifiable.Credential{ 173 ID: "https://issuer.oidp.uscis.gov/credentials/83627465", 174 Context: []string{ 175 verifiable.ContextURI, 176 "https://www.w3.org/2018/credentials/examples/v1", 177 "https://w3id.org/security/bbs/v1", 178 }, 179 Types: []string{ 180 "VerifiableCredential", 181 "UniversityDegreeCredential", 182 }, 183 Subject: verifiable.Subject{ 184 ID: "did:example:b34ca6cd37bbf23", 185 CustomFields: map[string]interface{}{ 186 "name": "Jayden Doe", 187 "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1", 188 "degree": map[string]interface{}{ 189 "degree": "MIT", 190 "degreeSchool": "MIT school", 191 "type": "BachelorDegree", 192 }, 193 }, 194 }, 195 Issued: &util.TimeWrapper{ 196 Time: time.Now(), 197 }, 198 Expired: &util.TimeWrapper{ 199 Time: time.Now().AddDate(1, 0, 0), 200 }, 201 Issuer: verifiable.Issuer{ 202 ID: "did:example:489398593", 203 }, 204 CustomFields: map[string]interface{}{ 205 "identifier": "83627465", 206 "name": "Permanent Resident Card", 207 "description": "Government of Example Permanent Resident Card.", 208 }, 209 } 210 211 publicKey, privateKey, err := bbs12381g2pub.GenerateKeyPair(sha256.New, nil) 212 require.NoError(t, err) 213 214 srcPublicKey, err := publicKey.Marshal() 215 require.NoError(t, err) 216 217 signer, err := newBBSSigner(privateKey) 218 require.NoError(t, err) 219 220 lddl := createTestJSONLDDocumentLoader(t) 221 222 require.NoError(t, vc.AddLinkedDataProof(&verifiable.LinkedDataProofContext{ 223 SignatureType: "BbsBlsSignature2020", 224 SignatureRepresentation: verifiable.SignatureProofValue, 225 Suite: bbsblssignature2020.New(suite.WithSigner(signer)), 226 VerificationMethod: "did:example:123456#key1", 227 }, jsonld.WithDocumentLoader(lddl))) 228 229 matched, err := pd.MatchSubmissionRequirement([]*verifiable.Credential{vc}, lddl, 230 presexch.WithSelectiveDisclosureApply(), 231 presexch.WithSDCredentialOptions(verifiable.WithJSONLDDocumentLoader(lddl), 232 verifiable.WithPublicKeyFetcher(verifiable.SingleKey(srcPublicKey, "Bls12381G2Key2020"))), 233 ) 234 require.NoError(t, err) 235 require.Len(t, matched, 1) 236 require.Equal(t, 1, len(matched[0].Descriptors)) 237 require.Equal(t, 1, len(matched[0].Descriptors[0].MatchedVCs)) 238 239 matchedVC := matched[0].Descriptors[0].MatchedVCs[0] 240 241 require.Equal(t, vc.ID, matchedVC.ID) 242 243 subject := matchedVC.Subject.([]verifiable.Subject)[0] 244 degree := subject.CustomFields["degree"] 245 require.NotNil(t, degree) 246 247 degreeMap, ok := degree.(map[string]interface{}) 248 require.True(t, ok) 249 250 require.Equal(t, "MIT school", degreeMap["degreeSchool"]) 251 require.Equal(t, "BachelorDegree", degreeMap["type"]) 252 require.Empty(t, degreeMap["degree"]) 253 require.Equal(t, "did:example:b34ca6cd37bbf23", subject.ID) 254 require.Empty(t, subject.CustomFields["spouse"]) 255 require.Empty(t, matchedVC.CustomFields["name"]) 256 257 require.NotEmpty(t, matchedVC.Proofs) 258 }) 259 260 t.Run("Checks schema", func(t *testing.T) { 261 pd := &presexch.PresentationDefinition{ID: uuid.New().String()} 262 263 vp, err := pd.MatchSubmissionRequirement(nil, nil) 264 265 require.EqualError(t, err, "presentation_definition: input_descriptors is required") 266 require.Nil(t, vp) 267 }) 268 269 t.Run("Checks submission requirements (no descriptor)", func(t *testing.T) { 270 issuerID := uuid.New().String() 271 272 pd := &presexch.PresentationDefinition{ 273 ID: uuid.New().String(), 274 SubmissionRequirements: []*presexch.SubmissionRequirement{ 275 { 276 Rule: "all", 277 From: "A", 278 }, 279 { 280 Rule: "pick", 281 Count: 1, 282 FromNested: []*presexch.SubmissionRequirement{ 283 { 284 Rule: "all", 285 From: "teenager", 286 }, 287 }, 288 }, 289 }, 290 InputDescriptors: []*presexch.InputDescriptor{{ 291 ID: uuid.New().String(), 292 Group: []string{"A"}, 293 Schema: []*presexch.Schema{{ 294 URI: verifiable.ContextURI, 295 }}, 296 Constraints: &presexch.Constraints{ 297 SubjectIsIssuer: &subIsIssuerRequired, 298 Fields: []*presexch.Field{{ 299 Path: []string{"$.first_name", "$.last_name"}, 300 }}, 301 }, 302 }}, 303 } 304 305 result, err := pd.MatchSubmissionRequirement([]*verifiable.Credential{ 306 { 307 Context: []string{verifiable.ContextURI}, 308 Types: []string{verifiable.VCType}, 309 ID: uuid.New().String(), 310 CustomFields: map[string]interface{}{ 311 "first_name": "Jesse", 312 }, 313 }, { 314 ID: uuid.New().String(), 315 Subject: []verifiable.Subject{{ID: issuerID}}, 316 Issuer: verifiable.Issuer{ID: issuerID}, 317 CustomFields: map[string]interface{}{ 318 "first_name": "Jesse", 319 "last_name": "Travis", 320 "age": 17, 321 }, 322 }, 323 }, docLoader) 324 325 require.EqualError(t, err, "no descriptors for from: teenager") 326 require.Nil(t, result) 327 }) 328 }