From cc6786271d7df92db1353c5780b74655e9a28ece Mon Sep 17 00:00:00 2001 From: Thomas Diesler Date: Fri, 10 Apr 2026 15:22:23 +0200 Subject: [PATCH] [OID4VCI] Add comprehensive testing for pre-installed vc configs Signed-off-by: Thomas Diesler --- .../SupportedCredentialConfiguration.java | 2 - .../tests/oid4vc/OID4VCBasicWallet.java | 38 +++- .../oid4vc/OID4VCINaturalPersonTest.java | 169 ++++++++++++++++++ .../tests/oid4vc/OID4VCIssuerTestBase.java | 44 +++-- .../tests/oid4vc/OID4VCProofTestUtils.java | 2 +- .../tests/oid4vc/OID4VCPublicClientTest.java | 5 +- .../tests/oid4vc/OID4VCTestContext.java | 2 +- .../oid4vc/OID4VCredentialByScopeTest.java | 4 +- .../OID4VCredentialOfferAuthCodeTest.java | 8 +- .../OID4VCAuthorizationCodeFlowTestBase.java | 13 +- ...ID4VCAuthorizationDetailsFlowTestBase.java | 2 +- .../OID4VCPublicClientPreAuthTest.java | 2 +- .../OID4VCredentialOfferPreAuthTest.java | 4 +- .../util/oauth/oid4vc/OID4VCClient.java | 4 + 14 files changed, 252 insertions(+), 47 deletions(-) create mode 100644 tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCINaturalPersonTest.java diff --git a/services/src/main/java/org/keycloak/protocol/oid4vc/model/SupportedCredentialConfiguration.java b/services/src/main/java/org/keycloak/protocol/oid4vc/model/SupportedCredentialConfiguration.java index 6dcea6779a6b..fd1a8aea5273 100644 --- a/services/src/main/java/org/keycloak/protocol/oid4vc/model/SupportedCredentialConfiguration.java +++ b/services/src/main/java/org/keycloak/protocol/oid4vc/model/SupportedCredentialConfiguration.java @@ -41,8 +41,6 @@ public class SupportedCredentialConfiguration { private static final Logger LOGGER = Logger.getLogger(SupportedCredentialConfiguration.class); - public static final String DOT_SEPARATOR = "."; - @JsonIgnore private static final String FORMAT_KEY = "format"; @JsonIgnore diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCBasicWallet.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCBasicWallet.java index cd4343d26f3f..d57995446a39 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCBasicWallet.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCBasicWallet.java @@ -10,10 +10,13 @@ import java.util.Set; import java.util.function.Consumer; +import org.keycloak.OID4VCConstants; import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.crypto.KeyWrapper; +import org.keycloak.jose.jwk.JWK; +import org.keycloak.jose.jwk.JWKBuilder; import org.keycloak.jose.jws.JWSHeader; import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.JWSInputException; @@ -48,7 +51,6 @@ import static org.keycloak.constants.OID4VCIConstants.CREDENTIAL_OFFER_CREATE; import static org.keycloak.tests.oid4vc.OID4VCIssuerTestBase.TEST_PASSWORD; import static org.keycloak.tests.oid4vc.OID4VCIssuerTestBase.VCTestRealmConfig.TEST_REALM_NAME; -import static org.keycloak.tests.oid4vc.OID4VCProofTestUtils.createEcKeyPair; import static org.keycloak.tests.oid4vc.OID4VCTestContext.ACCESS_TOKEN_RESPONSE_ATTACHMENT_KEY; import static org.keycloak.tests.oid4vc.OID4VCTestContext.AUTHORIZATION_SERVER_METADATA_ATTACHMENT_KEY; import static org.keycloak.tests.oid4vc.OID4VCTestContext.AttachmentKey; @@ -160,19 +162,41 @@ public OIDCConfigurationRepresentation getAuthorizationServerMetadata(OID4VCTest return authServerMetadata; } - public Proofs generateJwtProof(OID4VCTestContext ctx, String user) { + public Proofs generateAttestationProof(OID4VCTestContext ctx, Consumer attestationKeyConsumer) { + KeyWrapper attestationKey = getECKeyPair(ctx, "attestationKey"); + KeyWrapper proofKey = getECKeyPair(ctx, "proofKey"); + + JWK proofJwk = JWKBuilder.create().ec(proofKey.getPublicKey()); + proofJwk.setKeyId(proofKey.getKid()); + proofJwk.setAlgorithm(proofKey.getAlgorithm()); + + String nonce = oauth.oid4vc().doNonceRequest().getNonce(); + Proofs proofs = Proofs.create(ProofType.ATTESTATION, OID4VCProofTestUtils.generateAttestationProof( + attestationKey, + nonce, + List.of(proofJwk), + List.of(OID4VCConstants.KeyAttestationResistanceLevels.HIGH), + List.of(OID4VCConstants.KeyAttestationResistanceLevels.HIGH), + null + )); + attestationKeyConsumer.accept(attestationKey); + return proofs; + } + + public Proofs generateJwtProof(OID4VCTestContext ctx) { String aud = getIssuerMetadata(ctx).getCredentialIssuer(); - String nonce = oauth.oid4vc().nonceRequest().send().getNonce(); - KeyWrapper kw = getECKeyPair(ctx, user, null); + String nonce = oauth.oid4vc().doNonceRequest().getNonce(); + KeyWrapper kw = getECKeyPair(ctx, null); return Proofs.create(ProofType.JWT, OID4VCProofTestUtils.generateJwtProof(aud, kw, nonce)); } - public KeyWrapper getECKeyPair(OID4VCTestContext ctx, String user, String keyId) { - String cacheKey = user + (keyId != null ? "_" + keyId : ""); + public KeyWrapper getECKeyPair(OID4VCTestContext ctx, String keyId) { + String cacheKey = keyId != null ? keyId : ctx.getHolder() + "_key"; AttachmentKey attachmentKey = new AttachmentKey<>(cacheKey, KeyWrapper.class); KeyWrapper kw = ctx.getAttachment(attachmentKey); if (kw == null) { - kw = createEcKeyPair(); + kw = OID4VCProofTestUtils.createEcKeyPair(); + if (keyId != null) kw.setKid(keyId); ctx.putAttachment(attachmentKey, kw); } return kw; diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCINaturalPersonTest.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCINaturalPersonTest.java new file mode 100644 index 000000000000..c4cf8205b0c8 --- /dev/null +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCINaturalPersonTest.java @@ -0,0 +1,169 @@ +package org.keycloak.tests.oid4vc; + +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.keycloak.TokenVerifier; +import org.keycloak.jose.jwk.JWK; +import org.keycloak.jose.jwk.JWKBuilder; +import org.keycloak.protocol.oid4vc.model.CredentialResponse; +import org.keycloak.protocol.oid4vc.model.CredentialScopeRepresentation; +import org.keycloak.protocol.oid4vc.model.Proofs; +import org.keycloak.protocol.oid4vc.model.VerifiableCredential; +import org.keycloak.representations.JsonWebToken; +import org.keycloak.sdjwt.IssuerSignedJWT; +import org.keycloak.sdjwt.vp.SdJwtVP; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testsuite.util.oauth.AccessTokenResponse; +import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse; +import org.keycloak.testsuite.util.oauth.PkceGenerator; +import org.keycloak.util.JsonSerialization; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.keycloak.OID4VCConstants.CLAIM_NAME_VCT; +import static org.keycloak.VCFormat.JWT_VC; +import static org.keycloak.VCFormat.SD_JWT_VC; +import static org.keycloak.constants.OID4VCIConstants.TRUSTED_KEYS_REALM_ATTR; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@KeycloakIntegrationTest(config = OID4VCIssuerTestBase.VCTestServerConfig.class) +public class OID4VCINaturalPersonTest extends OID4VCIssuerTestBase { + + @BeforeEach + void beforeEach() { + oauth.client(pubClient.getClientId()); + } + + @Test + public void testNaturalPersonJwt_AttestationProof() throws Exception { + + var ctx = new OID4VCTestContext(client, jwtNaturalPersonCredentialScope); + + Proofs proofs = wallet.generateAttestationProof(ctx, ak -> { + JWK trustedKey = JWKBuilder.create().kid(ak.getKid()).ec(ak.getPublicKey()); + String trustedKeyJson = JsonSerialization.valueAsString(List.of(trustedKey)); + setRealmAttributes(Map.of(TRUSTED_KEYS_REALM_ATTR, trustedKeyJson)); + }); + + String accessToken = getAccessToken(ctx); + CredentialResponse credResponse = getCredentialResponse(ctx, accessToken, proofs); + verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); + } + + @Test + public void testNaturalPersonJwt_JwtProof() throws Exception { + + var ctx = new OID4VCTestContext(client, jwtNaturalPersonCredentialScope); + + String accessToken = getAccessToken(ctx); + Proofs proofs = wallet.generateJwtProof(ctx); + CredentialResponse credResponse = getCredentialResponse(ctx, accessToken, proofs); + verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); + } + + @Test + public void testNaturalPersonSdJwt_AttestationProof() throws Exception { + + var ctx = new OID4VCTestContext(client, sdJwtNaturalPersonCredentialScope); + + Proofs proofs = wallet.generateAttestationProof(ctx, ak -> { + JWK trustedKey = JWKBuilder.create().kid(ak.getKid()).ec(ak.getPublicKey()); + String trustedKeyJson = JsonSerialization.valueAsString(List.of(trustedKey)); + setRealmAttributes(Map.of(TRUSTED_KEYS_REALM_ATTR, trustedKeyJson)); + }); + + String accessToken = getAccessToken(ctx); + CredentialResponse credResponse = getCredentialResponse(ctx, accessToken, proofs); + verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); + } + + + @Test + public void testNaturalPersonSdJwt_JwtProof() throws Exception { + + var ctx = new OID4VCTestContext(client, sdJwtNaturalPersonCredentialScope); + + String accessToken = getAccessToken(ctx); + Proofs proofs = wallet.generateJwtProof(ctx); + CredentialResponse credResponse = getCredentialResponse(ctx, accessToken, proofs); + verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); + } + + // Private --------------------------------------------------------------------------------------------------------- + + private String getAccessToken(OID4VCTestContext ctx) { + + PkceGenerator pkce = PkceGenerator.s256(); + AuthorizationEndpointResponse authResponse = wallet + .authorizationRequest() + .scope(ctx.getScope()) + .codeChallenge(pkce) + .send(ctx.getHolder(), TEST_PASSWORD); + String authCode = authResponse.getCode(); + assertNotNull(authCode, "No authCode"); + + AccessTokenResponse tokenResponse = wallet.accessTokenRequest(ctx, authCode) + .codeVerifier(pkce) + .send(); + String accessToken = wallet.validateHolderAccessToken(ctx, tokenResponse); + assertNotNull(accessToken, "No accessToken"); + return accessToken; + } + + private CredentialResponse getCredentialResponse(OID4VCTestContext ctx, String accessToken, Proofs proofs) { + + String authorizedIdentifier = ctx.getAuthorizedCredentialIdentifier(); + assertNotNull(authorizedIdentifier, "No authorized credential identifier"); + + CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) + .credentialIdentifier(authorizedIdentifier) + .proofs(proofs) + .send().getCredentialResponse(); + return credResponse; + } + + private void verifyCredentialResponse(OID4VCTestContext ctx, String expUser, CredentialResponse credResponse) throws Exception { + + CredentialScopeRepresentation credScope = ctx.getCredentialScope(); + String issuer = wallet.getIssuerMetadata(ctx).getCredentialIssuer(); + CredentialResponse.Credential credentialObj = credResponse.getCredentials().get(0); + assertNotNull(credentialObj, "The first credential in the array should not be null"); + + switch (credScope.getFormat()) { + case JWT_VC -> { + JsonWebToken vcJwt = TokenVerifier.create((String) credentialObj.getCredential(), JsonWebToken.class).getToken(); + assertEquals(issuer, vcJwt.getIssuer()); + Object vc = vcJwt.getOtherClaims().get("vc"); + VerifiableCredential credential = JsonSerialization.mapper.convertValue(vc, VerifiableCredential.class); + assertEquals(credScope.getSupportedCredentialTypes(), credential.getType()); + assertEquals(URI.create(issuer), credential.getIssuer()); + assertEquals(expUser + "@email.cz", credential.getCredentialSubject().getClaims().get("email")); + } + case SD_JWT_VC -> { + SdJwtVP sdJwtVP = SdJwtVP.of(credentialObj.getCredential().toString()); + IssuerSignedJWT issuerSignedJWT = sdJwtVP.getIssuerSignedJWT(); + JsonWebToken vcSdJwt = TokenVerifier.create(issuerSignedJWT.getJws(), JsonWebToken.class).getToken(); + Map otherClaims = vcSdJwt.getOtherClaims(); + assertEquals(issuer, vcSdJwt.getIssuer()); + assertEquals(credScope.getVct(), otherClaims.get(CLAIM_NAME_VCT)); + + Map claims = sdJwtVP.getClaims().values().stream().collect(Collectors.toMap( + arrayNode -> arrayNode.get(1).asText(), + arrayNode -> arrayNode.get(2).asText() + )); + assertEquals(Map.of( + "firstName", "Alice", + "familyName", "Wonderland", + "email", "alice@email.cz", + "sub", "did:key:5678" + ), claims); + } + } + } +} diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java index 168fd0d01f28..9b23c7c3e556 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java @@ -23,7 +23,6 @@ import org.keycloak.OID4VCConstants; import org.keycloak.VCFormat; import org.keycloak.admin.client.Keycloak; -import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientScopeResource; import org.keycloak.admin.client.resource.ClientScopesResource; import org.keycloak.admin.client.resource.RealmResource; @@ -113,6 +112,9 @@ public abstract class OID4VCIssuerTestBase { public static final String TEST_USER = "john"; public static final String TEST_PASSWORD = "password"; + public static final String jwtTypeNaturalPersonScopeName = "oid4vc_natural_person_jwt"; + public static final String sdJwtTypeNaturalPersonScopeName = "oid4vc_natural_person_sd"; + public static final String sdJwtTypeCredentialScopeName = "sd-jwt-credential"; public static final String sdJwtTypeCredentialConfigurationIdName = "sd-jwt-credential-config-id"; public static final String sdJwtTypeCredentialVct = "https://credentials.example.com/SD-JWT-Credential"; @@ -125,7 +127,7 @@ public abstract class OID4VCIssuerTestBase { @InjectRealm(config = VCTestRealmConfig.class) protected ManagedRealm testRealm; - @InjectClient(ref = "oid4vci-client", config = ConfidentialOID4VCIClient.class) + @InjectClient(ref = "oid4vci-client", config = PrivateOID4VCIClient.class) protected ManagedClient managedClient; @InjectClient(ref = OID4VCI_PUBLIC_CLIENT_ID, config = PublicOID4VCIClient.class) @@ -149,9 +151,11 @@ public abstract class OID4VCIssuerTestBase { @InjectKeycloakUrls protected KeycloakUrls keycloakUrls; - protected CredentialScopeRepresentation minimalJwtTypeCredentialScope; protected CredentialScopeRepresentation jwtTypeCredentialScope; protected CredentialScopeRepresentation sdJwtTypeCredentialScope; + protected CredentialScopeRepresentation minimalJwtTypeCredentialScope; + protected CredentialScopeRepresentation jwtNaturalPersonCredentialScope; + protected CredentialScopeRepresentation sdJwtNaturalPersonCredentialScope; protected ClientRepresentation client; protected ClientRepresentation pubClient; @@ -174,8 +178,10 @@ void beforeEachBase() { pubClient = managedPublicClient.admin().toRepresentation(); jwtTypeCredentialScope = requireExistingCredentialScope(jwtTypeCredentialScopeName); - minimalJwtTypeCredentialScope = requireExistingCredentialScope(minimalJwtTypeCredentialScopeName); sdJwtTypeCredentialScope = requireExistingCredentialScope(sdJwtTypeCredentialScopeName); + minimalJwtTypeCredentialScope = requireExistingCredentialScope(minimalJwtTypeCredentialScopeName); + jwtNaturalPersonCredentialScope = requireExistingCredentialScope(jwtTypeNaturalPersonScopeName); + sdJwtNaturalPersonCredentialScope = requireExistingCredentialScope(sdJwtTypeNaturalPersonScopeName); oauth.client(client.getClientId(), client.getSecret()); enableVerifiableCredentialEvents(testRealm); @@ -576,15 +582,23 @@ private List resolveProtocolMappers(String protoco } } - public static class ConfidentialOID4VCIClient implements ClientConfig { + public static class PrivateOID4VCIClient implements ClientConfig { @Override public ClientConfigBuilder configure(ClientConfigBuilder client) { + String[] optionalClientScopes = { + jwtTypeCredentialScopeName, + sdJwtTypeCredentialScopeName, + minimalJwtTypeCredentialScopeName, + jwtTypeNaturalPersonScopeName, + sdJwtTypeNaturalPersonScopeName, + "email" + }; client.clientId(OID4VCI_CLIENT_ID) .serviceAccountsEnabled(true) .directAccessGrantsEnabled(true) .defaultClientScopes("basic", "profile", "roles") - .optionalClientScopes(jwtTypeCredentialScopeName, minimalJwtTypeCredentialScopeName, sdJwtTypeCredentialScopeName, "email") + .optionalClientScopes(optionalClientScopes) .attribute(OID4VCI_ENABLED_ATTRIBUTE_KEY, "true") .redirectUris("*") .secret("test-secret"); @@ -596,10 +610,18 @@ public static class PublicOID4VCIClient implements ClientConfig { @Override public ClientConfigBuilder configure(ClientConfigBuilder client) { + String[] optionalClientScopes = { + jwtTypeCredentialScopeName, + sdJwtTypeCredentialScopeName, + minimalJwtTypeCredentialScopeName, + jwtTypeNaturalPersonScopeName, + sdJwtTypeNaturalPersonScopeName, + "email" + }; client.clientId(OID4VCI_PUBLIC_CLIENT_ID) .publicClient(true) .defaultClientScopes("basic", "profile", "roles") - .optionalClientScopes(jwtTypeCredentialScopeName, minimalJwtTypeCredentialScopeName, sdJwtTypeCredentialScopeName, "email") + .optionalClientScopes(optionalClientScopes) .redirectUris("http://127.0.0.1:8500/callback/oauth") .attribute(OID4VCI_ENABLED_ATTRIBUTE_KEY, "true") .attribute("pkce.code.challenge.method", "S256"); // require PKCE @@ -731,12 +753,4 @@ public long currentTimeMillis() { return currentTimeInS * 1000L; } } - - protected void setOid4vciEnabled(ClientRepresentation testClient, boolean enabled) { - ClientResource clientResource = testRealm.admin().clients().get(testClient.getId()); - Map attributes = Optional.ofNullable(testClient.getAttributes()).orElse(new HashMap<>()); - attributes.put(OID4VCI_ENABLED_ATTRIBUTE_KEY, String.valueOf(enabled)); - testClient.setAttributes(attributes); - clientResource.update(testClient); - } } diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCProofTestUtils.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCProofTestUtils.java index d68f59fa9ae7..ae058d761c78 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCProofTestUtils.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCProofTestUtils.java @@ -72,7 +72,7 @@ public static String generateAttestationProof( String certification ) { KeyAttestationJwtBody body = new KeyAttestationJwtBody(); - body.setIat((long) (System.currentTimeMillis() / 1000)); + body.setIat(System.currentTimeMillis() / 1000); body.setNonce(nonce); body.setAttestedKeys(attestedKeys); body.setKeyStorage(keyStorage); diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCPublicClientTest.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCPublicClientTest.java index c4d73615e5bf..a3bc5e7266cf 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCPublicClientTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCPublicClientTest.java @@ -56,8 +56,7 @@ public class OID4VCPublicClientTest extends OID4VCIssuerTestBase { @BeforeEach void beforeEach() { - // Reconfigure OAuthClient - oauth.client(pubClient.getClientId(), null); + oauth.client(pubClient.getClientId()); } @Test @@ -99,7 +98,7 @@ public void testCredentialFromPublicClient() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCTestContext.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCTestContext.java index 470470432c92..10dcfaf5d9c8 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCTestContext.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCTestContext.java @@ -167,7 +167,7 @@ public void putAttachment(AttachmentKey key, T value) { if (value != null) { attachments.put(key, value); } else { - attachments.remove(key, value); + attachments.remove(key); } } diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialByScopeTest.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialByScopeTest.java index a33e371c29b8..a3f2dc782336 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialByScopeTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialByScopeTest.java @@ -52,7 +52,7 @@ public void testNoOffer_Scope() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); @@ -93,7 +93,7 @@ public void testNoOffer_Scope_AuthDetails() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialOfferAuthCodeTest.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialOfferAuthCodeTest.java index d4a1bfcccc96..ca2a1b3dbaff 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialOfferAuthCodeTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCredentialOfferAuthCodeTest.java @@ -85,7 +85,7 @@ public void testAuthCodeOffer_Anonymous() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); @@ -163,7 +163,7 @@ public void testAuthCodeOffer_Anonymous_multipleOffers() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx1, accessToken1) .credentialIdentifier(authorizedIdentifier1) - .proofs(wallet.generateJwtProof(ctx1, ctx1.getHolder())) + .proofs(wallet.generateJwtProof(ctx1)) .send().getCredentialResponse(); verifyCredentialResponse(ctx1, ctx1.getHolder(), credResponse); @@ -222,7 +222,7 @@ public void testAuthCodeOffer_Anonymous_expiredOffer() throws Exception { IllegalStateException error = assertThrows(IllegalStateException.class, () -> wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse()); assertTrue(error.getMessage().contains("Credential offer has already expired"), error.getMessage()); timeOffSet.set(0); @@ -265,7 +265,7 @@ public void testAuthCodeOffer_Targeted() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/OID4VCAuthorizationCodeFlowTestBase.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/OID4VCAuthorizationCodeFlowTestBase.java index 04797926a051..d7102a3fa975 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/OID4VCAuthorizationCodeFlowTestBase.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/OID4VCAuthorizationCodeFlowTestBase.java @@ -34,7 +34,6 @@ import org.keycloak.testsuite.util.oauth.oid4vc.InvalidCredentialRequest; import org.keycloak.testsuite.util.oauth.oid4vc.Oid4vcCredentialResponse; -import org.jboss.logging.Logger; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -61,8 +60,6 @@ */ public abstract class OID4VCAuthorizationCodeFlowTestBase extends OID4VCIssuerTestBase { - private static final Logger logger = Logger.getLogger(OID4VCAuthorizationCodeFlowTestBase.class); - protected OID4VCTestContext ctx; /** Returns the credential format supported by this test (e.g. {@code "jwt_vc"} or {@code "sd_jwt_vc"}). */ @@ -97,28 +94,28 @@ private void cleanupState() { try { wallet.logout(TEST_USER); } catch (Exception e) { - logger.warn("Failed to logout user during cleanup", e); + log.warn("Failed to logout user during cleanup", e); } // 2. User profile restoration try { resetTestUser(); } catch (Exception e) { - logger.warn("Failed to reset test user", e); + log.warn("Failed to reset test user", e); } // 3. Consent cleanup try { clearUserConsents(); } catch (Exception e) { - logger.warn("Failed to clear user consents", e); + log.warn("Failed to clear user consents", e); } // 4. Event cleanup try { events.clear(); } catch (Exception e) { - logger.warn("Failed to clear events", e); + log.warn("Failed to clear events", e); } // 5. Browser-side cookie cleanup (VERY IMPORTANT to prevent NoSuchElementException: username) @@ -128,7 +125,7 @@ private void cleanupState() { driver.driver().navigate().to("about:blank"); } } catch (Exception e) { - logger.warn("Failed to cleanup browser state", e); + log.warn("Failed to cleanup browser state", e); } } diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCAuthorizationDetailsFlowTestBase.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCAuthorizationDetailsFlowTestBase.java index 677966a842a6..c6a4c7ed4c9a 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCAuthorizationDetailsFlowTestBase.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCAuthorizationDetailsFlowTestBase.java @@ -186,7 +186,7 @@ private void runAuthorizationDetailsTest( if (credentialRequestSupplier == null) { credentialRequestSupplier = () -> new CredentialRequest() .setCredentialIdentifier(expCredentialIdentifier) - .setProofs(wallet.generateJwtProof(ctx, ctx.getHolder())); + .setProofs(wallet.generateJwtProof(ctx)); } // Update the vc.credential_identifier attribute diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCPublicClientPreAuthTest.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCPublicClientPreAuthTest.java index 24db6ac12827..5b5d685e165b 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCPublicClientPreAuthTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCPublicClientPreAuthTest.java @@ -80,7 +80,7 @@ public void testCredentialFromPreAuthCode() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); diff --git a/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCredentialOfferPreAuthTest.java b/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCredentialOfferPreAuthTest.java index 24cdf9958535..091b884e7cf5 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCredentialOfferPreAuthTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oid4vc/preauth/OID4VCredentialOfferPreAuthTest.java @@ -92,7 +92,7 @@ public void testPreAuthOffer_SelfIssued() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getIssuer(), credResponse); @@ -126,7 +126,7 @@ public void testPreAuthOffer_Targeted() throws Exception { // CredentialResponse credResponse = wallet.credentialRequest(ctx, accessToken) .credentialIdentifier(authorizedIdentifier) - .proofs(wallet.generateJwtProof(ctx, ctx.getHolder())) + .proofs(wallet.generateJwtProof(ctx)) .send().getCredentialResponse(); verifyCredentialResponse(ctx, ctx.getHolder(), credResponse); diff --git a/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/oauth/oid4vc/OID4VCClient.java b/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/oauth/oid4vc/OID4VCClient.java index 6c1902cab7fc..47b2154f31be 100644 --- a/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/oauth/oid4vc/OID4VCClient.java +++ b/tests/utils-shared/src/main/java/org/keycloak/testsuite/util/oauth/oid4vc/OID4VCClient.java @@ -56,4 +56,8 @@ public AccessTokenResponse doPreAuthorizedCodeGrantRequest(String preAuthCode) { public Oid4vcNonceRequest nonceRequest() { return new Oid4vcNonceRequest(client); } + + public Oid4vcNonceResponse doNonceRequest() { + return nonceRequest().send(); + } }