|
58 | 58 | import static org.hamcrest.Matchers.greaterThan;
|
59 | 59 | import static org.junit.jupiter.api.Assertions.assertEquals;
|
60 | 60 | import static org.junit.jupiter.api.Assertions.assertThrows;
|
| 61 | +import static org.junit.jupiter.api.Assertions.assertNull; |
61 | 62 | import static org.mockito.ArgumentMatchers.any;
|
62 | 63 | import static org.mockito.Mockito.when;
|
63 | 64 | import static uk.gov.di.ipv.core.library.domain.Cri.BAV;
|
@@ -305,6 +306,119 @@ void fetchVerifiableCredential_whenCalledAgainstBavCri_retrievesAVcWithACi(
|
305 | 306 | });
|
306 | 307 | }
|
307 | 308 |
|
| 309 | + @Pact(provider = "BavCriProvider", consumer = "IpvCoreBack") |
| 310 | + public RequestResponsePact validRequestReturnsBavResponseWithoutCi( |
| 311 | + PactDslWithProvider builder) { |
| 312 | + return builder.given("dummyApiKey is a valid api key") |
| 313 | + .given("test-subject is a valid subject") |
| 314 | + .given("dummyBavComponentId is a valid issuer") |
| 315 | + .given("VC evidence failedCheckDetails identityCheckPolicy is none") |
| 316 | + .given("VC evidence failedCheckDetails checkMethod is data") |
| 317 | + .given("VC evidence validityScore is 0") |
| 318 | + .given("VC evidence strengthScore is 3") |
| 319 | + .given("VC evidence txn is dummyTxn") |
| 320 | + .given("VC evidence credentialSubject contains bankAccount") |
| 321 | + .given("VC bankAccount accountNumber is 11111117") |
| 322 | + .given("VC bankAccount sortCode is 204578") |
| 323 | + .given("VC is for Bob Fossil") |
| 324 | + .uponReceiving("Valid credential request for BAV failed VC with no CIs") |
| 325 | + .path("/userinfo") |
| 326 | + .method("POST") |
| 327 | + .headers("x-api-key", PRIVATE_API_KEY, "Authorization", "Bearer dummyAccessToken") |
| 328 | + .willRespondWith() |
| 329 | + .status(200) |
| 330 | + .body( |
| 331 | + newJsonBody( |
| 332 | + body -> { |
| 333 | + var jwtBuilder = |
| 334 | + new PactJwtBuilder( |
| 335 | + VALID_VC_HEADER, |
| 336 | + FAILED_BAV_NO_CI_VC_BODY, |
| 337 | + FAILED_BAV_NO_CI_VC_SIGNATURE); |
| 338 | + |
| 339 | + body.stringValue("sub", "test-subject"); |
| 340 | + body.minMaxArrayLike( |
| 341 | + "https://vocab.account.gov.uk/v1/credentialJWT", |
| 342 | + 1, |
| 343 | + 1, |
| 344 | + PactDslJsonRootValue.stringMatcher( |
| 345 | + jwtBuilder |
| 346 | + .buildRegexMatcherIgnoringSignature(), |
| 347 | + jwtBuilder.buildJwt()), |
| 348 | + 1); |
| 349 | + }) |
| 350 | + .build()) |
| 351 | + .toPact(); |
| 352 | + } |
| 353 | + |
| 354 | + @Test |
| 355 | + @PactTestFor(pactMethod = "validRequestReturnsBavResponseWithoutCi") |
| 356 | + void fetchVerifiableCredential_whenCalledAgainstBavCri_retrievesAVcWithoutACi( |
| 357 | + MockServer mockServer) |
| 358 | + throws URISyntaxException, CriApiException, JsonProcessingException { |
| 359 | + // Arrange |
| 360 | + var credentialIssuerConfig = getMockCredentialIssuerConfig(mockServer); |
| 361 | + configureMockConfigService(credentialIssuerConfig); |
| 362 | + |
| 363 | + // We need to generate a fixed request, so we set the secure token and expiry to constant |
| 364 | + // values. |
| 365 | + var underTest = |
| 366 | + new CriApiService( |
| 367 | + mockConfigService, mockSignerFactory, mockSecureTokenHelper, CURRENT_TIME); |
| 368 | + |
| 369 | + // Act |
| 370 | + var verifiableCredentialResponse = |
| 371 | + underTest.fetchVerifiableCredential( |
| 372 | + new BearerAccessToken("dummyAccessToken"), BAV, CRI_OAUTH_SESSION_ITEM); |
| 373 | + |
| 374 | + // Assert |
| 375 | + var verifiableCredentialJwtValidator = getVerifiableCredentialJwtValidator(); |
| 376 | + verifiableCredentialResponse |
| 377 | + .getVerifiableCredentials() |
| 378 | + .forEach( |
| 379 | + credential -> { |
| 380 | + System.out.println(credential); |
| 381 | + try { |
| 382 | + var vc = |
| 383 | + verifiableCredentialJwtValidator.parseAndValidate( |
| 384 | + TEST_USER, |
| 385 | + BAV, |
| 386 | + credential, |
| 387 | + EC_PRIVATE_KEY_JWK, |
| 388 | + TEST_ISSUER, |
| 389 | + false); |
| 390 | + |
| 391 | + JsonNode vcClaim = |
| 392 | + OBJECT_MAPPER |
| 393 | + .readTree(vc.getClaimsSet().toString()) |
| 394 | + .get("vc"); |
| 395 | + |
| 396 | + JsonNode credentialSubject = vcClaim.get("credentialSubject"); |
| 397 | + JsonNode evidence = vcClaim.get("evidence").get(0); |
| 398 | + |
| 399 | + JsonNode ciNode = evidence.get("ci"); |
| 400 | + JsonNode nameParts = |
| 401 | + credentialSubject.get("name").get(0).get("nameParts"); |
| 402 | + |
| 403 | + assertNull(ciNode); |
| 404 | + |
| 405 | + JsonNode bankAccountNode = |
| 406 | + credentialSubject.get("bankAccount").get(0); |
| 407 | + |
| 408 | + assertEquals( |
| 409 | + "11111117", bankAccountNode.get("accountNumber").asText()); |
| 410 | + assertEquals("204578", bankAccountNode.get("sortCode").asText()); |
| 411 | + |
| 412 | + assertEquals("GivenName", nameParts.get(0).get("type").asText()); |
| 413 | + assertEquals("FamilyName", nameParts.get(1).get("type").asText()); |
| 414 | + assertEquals("Bob", nameParts.get(0).get("value").asText()); |
| 415 | + assertEquals("Fossil", nameParts.get(1).get("value").asText()); |
| 416 | + } catch (VerifiableCredentialException | JsonProcessingException e) { |
| 417 | + throw new RuntimeException(e); |
| 418 | + } |
| 419 | + }); |
| 420 | + } |
| 421 | + |
308 | 422 | @Pact(provider = "BavCriProvider", consumer = "IpvCoreBack")
|
309 | 423 | public RequestResponsePact invalidAccessTokenReturns401(PactDslWithProvider builder) {
|
310 | 424 | return builder.given("dummyApiKey is a valid api key")
|
@@ -717,4 +831,70 @@ private static OauthCriConfig getMockCredentialIssuerConfig(MockServer mockServe
|
717 | 831 | // change each time we run the tests.
|
718 | 832 | private static final String FAILED_BAV_VC_SIGNATURE =
|
719 | 833 | "JlGnDKxWr2ELrHzh1txDvG21xrINyWQ6fu9gTnoZaWlZzIe5pKrawn9ulwJ2B-0BUvUHMAKURj7sPODiOL-v_w"; // pragma: allowlist secret
|
| 834 | + |
| 835 | + private static final String FAILED_BAV_NO_CI_VC_BODY = |
| 836 | + """ |
| 837 | + { |
| 838 | + "nbf": 4070908800, |
| 839 | + "iat": 4070908800, |
| 840 | + "jti": "jti", |
| 841 | + "iss": "dummyBavComponentId", |
| 842 | + "sub": "test-subject", |
| 843 | + "vc": { |
| 844 | + "@context": [ |
| 845 | + "https://www.w3.org/2018/credentials/v1", |
| 846 | + "https://vocab.account.gov.uk/contexts/identity-v1.jsonld" |
| 847 | + ], |
| 848 | + "type": [ |
| 849 | + "VerifiableCredential", |
| 850 | + "IdentityCheckCredential" |
| 851 | + ], |
| 852 | + "credentialSubject": { |
| 853 | + "name": [ |
| 854 | + { |
| 855 | + "nameParts": [ |
| 856 | + { |
| 857 | + "type": "GivenName", |
| 858 | + "value": "Bob" |
| 859 | + }, |
| 860 | + { |
| 861 | + "type": "FamilyName", |
| 862 | + "value": "Fossil" |
| 863 | + } |
| 864 | + ] |
| 865 | + } |
| 866 | + ], |
| 867 | + "birthDate": [ |
| 868 | + { |
| 869 | + "value": "1960-02-02" |
| 870 | + } |
| 871 | + ], |
| 872 | + "bankAccount": [ |
| 873 | + { |
| 874 | + "sortCode": "204578", |
| 875 | + "accountNumber": "11111117" |
| 876 | + } |
| 877 | + ] |
| 878 | + }, |
| 879 | + "evidence": [ |
| 880 | + { |
| 881 | + "type": "IdentityCheck", |
| 882 | + "strengthScore": 3, |
| 883 | + "validityScore": 0, |
| 884 | + "failedCheckDetails": [ |
| 885 | + { |
| 886 | + "checkMethod": "data", |
| 887 | + "identityCheckPolicy": "none" |
| 888 | + } |
| 889 | + ] |
| 890 | + } |
| 891 | + ] |
| 892 | + } |
| 893 | + } |
| 894 | + """; |
| 895 | + // If we generate the signature in code it will be different each time, so we need to generate a |
| 896 | + // valid signature (using https://jwt.io works well) and record it here so the PACT file doesn't |
| 897 | + // change each time we run the tests. |
| 898 | + private static final String FAILED_BAV_NO_CI_VC_SIGNATURE = |
| 899 | + "SP4lmGdIwzBanmeQEtwJoBVY7dfBPrFLNnIbNPe8dYYqiqvrqM7KGNgoj5AZK4-QMBdeG6f5wClWb0DcA0cKAg"; // pragma: allowlist secret |
720 | 900 | }
|
0 commit comments