From 333aee90d1dfae652397876d0d0ec5fa08e408d0 Mon Sep 17 00:00:00 2001 From: Paddy Buckley Date: Fri, 23 Oct 2026 14:53:32 +0100 Subject: [PATCH] Migrate IdTokenEncryptionTest.java to the new test framework (#54269) Closes #53289 Signed-off-by: Paddy Buckley --- .../tests/oidc/AbstractOIDCScopeTest.java | 70 +++++ .../AuthorizationTokenEncryptionTest.java | 94 +------ .../tests}/oidc/IdTokenEncryptionTest.java | 257 +++++++----------- 3 files changed, 171 insertions(+), 250 deletions(-) rename {testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite => tests/base/src/test/java/org/keycloak/tests}/oidc/IdTokenEncryptionTest.java (59%) diff --git a/tests/base/src/test/java/org/keycloak/tests/oidc/AbstractOIDCScopeTest.java b/tests/base/src/test/java/org/keycloak/tests/oidc/AbstractOIDCScopeTest.java index 56defd22b12..81faf8e3517 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oidc/AbstractOIDCScopeTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oidc/AbstractOIDCScopeTest.java @@ -17,25 +17,45 @@ package org.keycloak.tests.oidc; +import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import jakarta.ws.rs.core.Response; + import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator; +import org.keycloak.common.util.Base64Url; +import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.crypto.AesCbcHmacShaContentEncryptionProvider; +import org.keycloak.crypto.AesGcmContentEncryptionProvider; +import org.keycloak.crypto.RsaCekManagementProvider; import org.keycloak.events.Details; +import org.keycloak.jose.JOSEHeader; +import org.keycloak.jose.jwe.JWEConstants; +import org.keycloak.jose.jwe.JWEHeader; +import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider; +import org.keycloak.jose.jwe.enc.JWEEncryptionProvider; +import org.keycloak.keys.Attributes; +import org.keycloak.keys.GeneratedEcdsaKeyProviderFactory; +import org.keycloak.keys.KeyProvider; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; +import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.EventRepresentation; import org.keycloak.testframework.annotations.InjectEvents; import org.keycloak.testframework.events.EventAssertion; import org.keycloak.testframework.events.Events; import org.keycloak.testframework.oauth.OAuthClient; import org.keycloak.testframework.oauth.annotations.InjectOAuthClient; +import org.keycloak.testframework.realm.ManagedRealm; import org.keycloak.testframework.ui.annotations.InjectPage; import org.keycloak.testframework.ui.page.ErrorPage; import org.keycloak.testframework.ui.page.LoginPage; import org.keycloak.testframework.ui.page.LoginTotpPage; import org.keycloak.testframework.ui.page.OAuthGrantPage; +import org.keycloak.testframework.util.ApiUtil; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; +import org.keycloak.util.JsonSerialization; import org.keycloak.util.TokenUtil; import org.junit.jupiter.api.Assertions; @@ -114,6 +134,56 @@ public abstract class AbstractOIDCScopeTest { loginPage.submit(); } + protected JWEEncryptionProvider getJweEncryptionProvider(String encAlgorithm) { + JWEEncryptionProvider jweEncryptionProvider = null; + switch (encAlgorithm) { + case JWEConstants.A128GCM: + case JWEConstants.A192GCM: + case JWEConstants.A256GCM: + jweEncryptionProvider = new AesGcmContentEncryptionProvider(null, encAlgorithm).jweEncryptionProvider(); + break; + case JWEConstants.A128CBC_HS256: + case JWEConstants.A192CBC_HS384: + case JWEConstants.A256CBC_HS512: + jweEncryptionProvider = new AesCbcHmacShaContentEncryptionProvider(null, encAlgorithm).jweEncryptionProvider(); + break; + default: + break; + } + return jweEncryptionProvider; + } + + protected JOSEHeader getHeader(String base64Header) { + try { + byte[] decodedHeader = Base64Url.decode(base64Header); + return JsonSerialization.readValue(decodedHeader, JWEHeader.class); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + + protected JWEAlgorithmProvider getJweAlgorithmProvider(String algAlgorithm) { + return new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider(); + } + + protected void registerEcKeyProvider(String ecCurve, ManagedRealm realm) { + ComponentRepresentation rep = new ComponentRepresentation(); + rep.setName("ecdsa-" + ecCurve); + rep.setParentId(realm.admin().toRepresentation().getId()); + rep.setProviderId(GeneratedEcdsaKeyProviderFactory.ID); + rep.setProviderType(KeyProvider.class.getName()); + rep.setConfig(new MultivaluedHashMap<>()); + rep.getConfig().putSingle(Attributes.PRIORITY_KEY, Long.toString(System.currentTimeMillis())); + rep.getConfig().putSingle("active", "true"); + rep.getConfig().putSingle("enabled", "true"); + rep.getConfig().putSingle(GeneratedEcdsaKeyProviderFactory.ECDSA_ELLIPTIC_CURVE_KEY, ecCurve); + + try (Response response = realm.admin().components().add(rep)) { + String id = ApiUtil.getCreatedId(response); + realm.cleanup().add(r -> r.components().component(id).remove()); + } + } + static class Tokens { final IDToken idToken; final AccessToken accessToken; diff --git a/tests/base/src/test/java/org/keycloak/tests/oidc/AuthorizationTokenEncryptionTest.java b/tests/base/src/test/java/org/keycloak/tests/oidc/AuthorizationTokenEncryptionTest.java index 13ba9a5fac2..29d49f07362 100644 --- a/tests/base/src/test/java/org/keycloak/tests/oidc/AuthorizationTokenEncryptionTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oidc/AuthorizationTokenEncryptionTest.java @@ -16,46 +16,29 @@ */ package org.keycloak.tests.oidc; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.PrivateKey; import java.util.Map; -import jakarta.ws.rs.core.Response; - import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.common.util.Base64Url; -import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.PemUtils; -import org.keycloak.crypto.AesCbcHmacShaContentEncryptionProvider; -import org.keycloak.crypto.AesGcmContentEncryptionProvider; import org.keycloak.crypto.Algorithm; -import org.keycloak.crypto.RsaCekManagementProvider; -import org.keycloak.jose.JOSEHeader; import org.keycloak.jose.jwe.JWEConstants; import org.keycloak.jose.jwe.JWEException; import org.keycloak.jose.jwe.JWEHeader; import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider; import org.keycloak.jose.jwe.enc.JWEEncryptionProvider; -import org.keycloak.keys.Attributes; -import org.keycloak.keys.GeneratedEcdsaKeyProviderFactory; -import org.keycloak.keys.KeyProvider; import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper; import org.keycloak.representations.AuthorizationResponseToken; import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.testframework.annotations.InjectRealm; import org.keycloak.testframework.annotations.KeycloakIntegrationTest; import org.keycloak.testframework.injection.LifeCycle; import org.keycloak.testframework.oauth.JwksProvider; import org.keycloak.testframework.oauth.annotations.InjectJwksProvider; import org.keycloak.testframework.realm.ManagedRealm; -import org.keycloak.testframework.realm.RealmBuilder; -import org.keycloak.testframework.realm.RealmConfig; -import org.keycloak.testframework.realm.UserBuilder; -import org.keycloak.testframework.util.ApiUtil; +import org.keycloak.tests.common.BasicRealmWithUserConfig; import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse; -import org.keycloak.util.JsonSerialization; import org.keycloak.util.TokenUtil; import org.junit.jupiter.api.Assertions; @@ -63,11 +46,11 @@ import org.junit.jupiter.api.Test; @KeycloakIntegrationTest public class AuthorizationTokenEncryptionTest extends AbstractOIDCScopeTest{ - private static final String USERNAME = "test-user@localhost"; + private static final String USERNAME = "basic-user"; private static final String PASSWORD = "password"; private static final String STATE = "OpenIdConnect.AuthenticationProperties=2302984sdlk"; - @InjectRealm(config = AuthorizationTokenEncryptionRealmConfig.class, lifecycle = LifeCycle.METHOD) + @InjectRealm(config = BasicRealmWithUserConfig.class, lifecycle = LifeCycle.METHOD) ManagedRealm managedRealm; @InjectJwksProvider @@ -75,7 +58,7 @@ public class AuthorizationTokenEncryptionTest extends AbstractOIDCScopeTest{ @Test public void testAuthorizationEncryptionAlgRSA1_5EncA128CBC_HS256() { - registerEcKeyProvider("P-256"); + registerEcKeyProvider("P-256",managedRealm); testAuthorizationTokenSignatureAndEncryption(Algorithm.ES256, JWEConstants.RSA1_5, JWEConstants.A128CBC_HS256); } @@ -106,7 +89,7 @@ public class AuthorizationTokenEncryptionTest extends AbstractOIDCScopeTest{ @Test public void testAuthorizationEncryptionAlgRSA_OAEPEncA128CBC_HS256() { - registerEcKeyProvider("P-521"); + registerEcKeyProvider("P-521",managedRealm); testAuthorizationTokenSignatureAndEncryption(Algorithm.ES512, JWEConstants.RSA_OAEP, JWEConstants.A128CBC_HS256); } @@ -122,7 +105,7 @@ public class AuthorizationTokenEncryptionTest extends AbstractOIDCScopeTest{ @Test public void testAuthorizationEncryptionAlgRSA_OAEP256EncA128CBC_HS256() { - registerEcKeyProvider("P-521"); + registerEcKeyProvider("P-521",managedRealm); testAuthorizationTokenSignatureAndEncryption(Algorithm.ES512, JWEConstants.RSA_OAEP_256, JWEConstants.A128CBC_HS256); } @@ -138,7 +121,7 @@ public class AuthorizationTokenEncryptionTest extends AbstractOIDCScopeTest{ @Test public void testAuthorizationEncryptionAlgRSA_OAEPEncA128GCM() { - registerEcKeyProvider("P-256"); + registerEcKeyProvider("P-256",managedRealm); testAuthorizationTokenSignatureAndEncryption(Algorithm.ES256, JWEConstants.RSA_OAEP, JWEConstants.A128GCM); } @@ -261,67 +244,4 @@ public class AuthorizationTokenEncryptionTest extends AbstractOIDCScopeTest{ clientResource.update(clientRep); } } - - private void registerEcKeyProvider(String ecCurve) { - ComponentRepresentation rep = new ComponentRepresentation(); - rep.setName("ecdsa-" + ecCurve); - rep.setParentId(managedRealm.admin().toRepresentation().getId()); - rep.setProviderId(GeneratedEcdsaKeyProviderFactory.ID); - rep.setProviderType(KeyProvider.class.getName()); - rep.setConfig(new MultivaluedHashMap<>()); - rep.getConfig().putSingle(Attributes.PRIORITY_KEY, Long.toString(System.currentTimeMillis())); - rep.getConfig().putSingle("active", "true"); - rep.getConfig().putSingle("enabled", "true"); - rep.getConfig().putSingle(GeneratedEcdsaKeyProviderFactory.ECDSA_ELLIPTIC_CURVE_KEY, ecCurve); - - try (Response response = managedRealm.admin().components().add(rep)) { - String id = ApiUtil.getCreatedId(response); - managedRealm.cleanup().add(r -> r.components().component(id).remove()); - } - } - - private JWEAlgorithmProvider getJweAlgorithmProvider(String algAlgorithm) { - return new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider(); - } - - private JWEEncryptionProvider getJweEncryptionProvider(String encAlgorithm) { - JWEEncryptionProvider jweEncryptionProvider = null; - switch (encAlgorithm) { - case JWEConstants.A128GCM: - case JWEConstants.A192GCM: - case JWEConstants.A256GCM: - jweEncryptionProvider = new AesGcmContentEncryptionProvider(null, encAlgorithm).jweEncryptionProvider(); - break; - case JWEConstants.A128CBC_HS256: - case JWEConstants.A192CBC_HS384: - case JWEConstants.A256CBC_HS512: - jweEncryptionProvider = new AesCbcHmacShaContentEncryptionProvider(null, encAlgorithm).jweEncryptionProvider(); - break; - default: - break; - } - return jweEncryptionProvider; - } - - private JOSEHeader getHeader(String base64Header) { - try { - byte[] decodedHeader = Base64Url.decode(base64Header); - return JsonSerialization.readValue(decodedHeader, JWEHeader.class); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - - private static class AuthorizationTokenEncryptionRealmConfig implements RealmConfig { - @Override - public RealmBuilder configure(RealmBuilder realm) { - return realm - .users(UserBuilder.create("test-user") - .email(USERNAME) - .username(USERNAME) - .firstName("test") - .lastName("user") - .password(PASSWORD)); - } - } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/IdTokenEncryptionTest.java b/tests/base/src/test/java/org/keycloak/tests/oidc/IdTokenEncryptionTest.java similarity index 59% rename from testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/IdTokenEncryptionTest.java rename to tests/base/src/test/java/org/keycloak/tests/oidc/IdTokenEncryptionTest.java index 9e4b8c8948b..bf7a40486f9 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/IdTokenEncryptionTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/oidc/IdTokenEncryptionTest.java @@ -14,23 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.testsuite.oidc; +package org.keycloak.tests.oidc; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.PrivateKey; -import java.util.List; import java.util.Map; import org.keycloak.OAuthErrorException; import org.keycloak.admin.client.resource.ClientResource; -import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.PemUtils; -import org.keycloak.crypto.AesCbcHmacShaContentEncryptionProvider; -import org.keycloak.crypto.AesGcmContentEncryptionProvider; import org.keycloak.crypto.Algorithm; -import org.keycloak.crypto.RsaCekManagementProvider; -import org.keycloak.jose.JOSEHeader; import org.keycloak.jose.jwe.JWEConstants; import org.keycloak.jose.jwe.JWEException; import org.keycloak.jose.jwe.JWEHeader; @@ -39,70 +32,34 @@ import org.keycloak.jose.jwe.enc.JWEEncryptionProvider; import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper; import org.keycloak.representations.IDToken; import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.testsuite.AbstractAdminTest; -import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; -import org.keycloak.testsuite.AssertEvents; -import org.keycloak.testsuite.admin.AdminApiUtil; -import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected; -import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls; -import org.keycloak.testsuite.client.resources.TestOIDCEndpointsApplicationResource; -import org.keycloak.testsuite.pages.ErrorPage; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.pages.OAuthGrantPage; -import org.keycloak.testsuite.util.ClientManager; -import org.keycloak.testsuite.util.TokenSignatureUtil; +import org.keycloak.testframework.annotations.InjectRealm; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testframework.injection.LifeCycle; +import org.keycloak.testframework.oauth.JwksProvider; +import org.keycloak.testframework.oauth.annotations.InjectJwksProvider; +import org.keycloak.testframework.realm.ManagedRealm; +import org.keycloak.tests.common.BasicRealmWithUserConfig; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse; -import org.keycloak.util.JsonSerialization; import org.keycloak.util.TokenUtil; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest { +@KeycloakIntegrationTest +public class IdTokenEncryptionTest extends AbstractOIDCScopeTest{ + private static final String USERNAME = "basic-user"; + private static final String PASSWORD = "password"; - @Rule - public AssertEvents events = new AssertEvents(this); + @InjectRealm(config = BasicRealmWithUserConfig.class, lifecycle = LifeCycle.METHOD) + ManagedRealm managedRealm; - @Page - protected LoginPage loginPage; - - @Page - protected OAuthGrantPage grantPage; - - @Page - protected ErrorPage errorPage; - - @Override - public void configureTestRealm(RealmRepresentation testRealm) { - } - - @Before - public void clientConfiguration() { - ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true).setServiceAccountsEnabled(true); - /* - * Configure the default client ID. Seems like OAuthClient is keeping the state of clientID - * For example: If some test case configure oauth.clientId("sample-public-client"), other tests - * will faile and the clientID will always be "sample-public-client - * @see AccessTokenTest#testAuthorizationNegotiateHeaderIgnored() - */ - oauth.client("test-app", "password"); - } - - @Override - public void addTestRealms(List testRealms) { - RealmRepresentation realm = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class); - testRealms.add(realm); - } + @InjectJwksProvider + JwksProvider jwksProvider; @Test public void testIdTokenEncryptionAlgRSA1_5EncA128CBC_HS256() { - // add key provider explicitly though DefaultKeyManager create fallback key provider if not exist - TokenSignatureUtil.registerKeyProvider("P-256", adminClient, testContext); + registerEcKeyProvider("P-256",managedRealm); testIdTokenSignatureAndEncryption(Algorithm.ES256, JWEConstants.RSA1_5, JWEConstants.A128CBC_HS256); } @@ -133,8 +90,7 @@ public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest { @Test public void testIdTokenEncryptionAlgRSA_OAEPEncA128CBC_HS256() { - // add key provider explicitly though DefaultKeyManager create fallback key provider if not exist - TokenSignatureUtil.registerKeyProvider("P-521", adminClient, testContext); + registerEcKeyProvider("P-521",managedRealm); testIdTokenSignatureAndEncryption(Algorithm.ES512, JWEConstants.RSA_OAEP, JWEConstants.A128CBC_HS256); } @@ -150,8 +106,7 @@ public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest { @Test public void testIdTokenEncryptionAlgRSA_OAEP256EncA128CBC_HS256() { - // add key provider explicitly though DefaultKeyManager create fallback key provider if not exist - TokenSignatureUtil.registerKeyProvider("P-521", adminClient, testContext); + registerEcKeyProvider("P-521",managedRealm); testIdTokenSignatureAndEncryption(Algorithm.ES512, JWEConstants.RSA_OAEP_256, JWEConstants.A128CBC_HS256); } @@ -167,8 +122,7 @@ public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest { @Test public void testIdTokenEncryptionAlgRSA_OAEPEncA128GCM() { - // add key provider explicitly though DefaultKeyManager create fallback key provider if not exist - TokenSignatureUtil.registerKeyProvider("P-256", adminClient, testContext); + registerEcKeyProvider("P-256",managedRealm); testIdTokenSignatureAndEncryption(Algorithm.ES256, JWEConstants.RSA_OAEP, JWEConstants.A128GCM); } @@ -187,15 +141,64 @@ public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest { testIdTokenSignatureAndEncryption(Algorithm.PS256, JWEConstants.RSA_OAEP, null); } + @Test + public void testIdTokenEncryptionWithoutEncryptionKEK() { + ClientResource clientResource = null; + ClientRepresentation clientRep = null; + try { + // generate and register signing/verifying key onto client, not encryption key + jwksProvider.generateKeys(Algorithm.RS256); + + clientResource = oauth.clientResource(); + clientRep = clientResource.toRepresentation(); + // set id token signature algorithm and encryption algorithms + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenSignedResponseAlg(Algorithm.RS256); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseAlg(JWEConstants.RSA1_5); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseEnc(JWEConstants.A128CBC_HS256); + // use and set jwks_url + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setUseJwksUrl(true); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setJwksUrl(jwksProvider.getUri()); + clientResource.update(clientRep); + + // open login form + oauth.loginForm().open(); + + // authenticate on login page + authenticatePassword(USERNAME,PASSWORD); + + // wait for response and get id token but should fail + AuthorizationEndpointResponse response = oauth.parseLoginResponse(); + AccessTokenResponse atr = oauth.doAccessTokenRequest(response.getCode()); + Assertions.assertEquals(OAuthErrorException.INVALID_REQUEST, atr.getError()); + Assertions.assertEquals("can not get encryption KEK", atr.getErrorDescription()); + + // get id token but failed with client_credentials grant type + oauth.scope("openid"); + AccessTokenResponse responseClientCredentials = oauth.client(clientRep.getClientId(), clientRep.getSecret()).doClientCredentialsGrantAccessTokenRequest(); + Assertions.assertEquals(OAuthErrorException.INVALID_REQUEST, responseClientCredentials.getError()); + Assertions.assertEquals("can not get encryption KEK", responseClientCredentials.getErrorDescription()); + } finally { + clientResource = oauth.clientResource(); + clientRep = clientResource.toRepresentation(); + // revert id token signature algorithm and encryption algorithms + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setAuthorizationSignedResponseAlg(Algorithm.RS256); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setAuthorizationEncryptedResponseAlg(null); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setAuthorizationEncryptedResponseEnc(null); + // revert jwks_url settings + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setUseJwksUrl(false); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setJwksUrl(null); + clientResource.update(clientRep); + } + } + private void testIdTokenSignatureAndEncryption(String sigAlgorithm, String algAlgorithm, String encAlgorithm) { ClientResource clientResource = null; ClientRepresentation clientRep = null; try { - // generate and register encryption key onto client - TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints(); - oidcClientEndpointsResource.generateKeys(algAlgorithm); + // generate and register encryption key onto client via JwksProvider + Map keyPair = jwksProvider.generateKeys(algAlgorithm); - clientResource = AdminApiUtil.findClientByClientId(adminClient.realm("test"), "test-app"); + clientResource = oauth.clientResource(); clientRep = clientResource.toRepresentation(); // set id token signature algorithm and encryption algorithms OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenSignedResponseAlg(sigAlgorithm); @@ -203,24 +206,29 @@ public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest { OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseEnc(encAlgorithm); // use and set jwks_url OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setUseJwksUrl(true); - String jwksUrl = TestApplicationResourceUrls.clientJwksUri(); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setJwksUrl(jwksUrl); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setJwksUrl(jwksProvider.getUri()); clientResource.update(clientRep); - // get id token - AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password"); + // open login form + oauth.loginForm().open(); + + // authenticate on login page + authenticatePassword(USERNAME,PASSWORD); + + + // wait for response and get authorization code + AuthorizationEndpointResponse response = oauth.parseLoginResponse(); String code = response.getCode(); + AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code); // parse JWE and JOSE Header String jweStr = tokenResponse.getIdToken(); String[] parts = jweStr.split("\\."); - Assertions.assertEquals(parts.length, 5); + Assertions.assertEquals(5, parts.length); // get decryption key - // not publickey , use privateKey - Map keyPair = oidcClientEndpointsResource.getKeysAsPem(); - PrivateKey decryptionKEK = PemUtils.decodePrivateKey(keyPair.get("privateKey")); + PrivateKey decryptionKEK = PemUtils.decodePrivateKey(keyPair.get(JwksProvider.PRIVATE_KEY)); // a nested JWT (signed and encrypted JWT) needs to set "JWT" to its JOSE Header's "cty" field JWEHeader jweHeader = (JWEHeader) getHeader(parts[0]); @@ -235,98 +243,21 @@ public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest { // verify JWS IDToken idToken = oauth.verifyIDToken(idTokenString); - Assertions.assertEquals("test-user@localhost", idToken.getPreferredUsername()); - Assertions.assertEquals("test-app", idToken.getIssuedFor()); + Assertions.assertEquals(USERNAME, idToken.getPreferredUsername()); + Assertions.assertEquals(oauth.getClientId(), idToken.getIssuedFor()); } catch (JWEException e) { - Assertions.fail(); + Assertions.fail(e); } finally { - clientResource = AdminApiUtil.findClientByClientId(adminClient.realm("test"), "test-app"); + clientResource = oauth.clientResource(); clientRep = clientResource.toRepresentation(); // revert id token signature algorithm and encryption algorithms - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenSignedResponseAlg(Algorithm.RS256); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseAlg(null); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseEnc(null); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setAuthorizationSignedResponseAlg(Algorithm.RS256); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setAuthorizationEncryptedResponseAlg(null); + OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setAuthorizationEncryptedResponseEnc(null); // revert jwks_url settings OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setUseJwksUrl(false); OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setJwksUrl(null); clientResource.update(clientRep); } } - - private JWEAlgorithmProvider getJweAlgorithmProvider(String algAlgorithm) { - return new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider(); - } - private JWEEncryptionProvider getJweEncryptionProvider(String encAlgorithm) { - JWEEncryptionProvider jweEncryptionProvider = null; - switch(encAlgorithm) { - case JWEConstants.A128GCM: - case JWEConstants.A192GCM: - case JWEConstants.A256GCM: - jweEncryptionProvider = new AesGcmContentEncryptionProvider(null, encAlgorithm).jweEncryptionProvider(); - break; - case JWEConstants.A128CBC_HS256: - case JWEConstants.A192CBC_HS384: - case JWEConstants.A256CBC_HS512: - jweEncryptionProvider = new AesCbcHmacShaContentEncryptionProvider(null, encAlgorithm).jweEncryptionProvider(); - break; - } - return jweEncryptionProvider; - } - - private JOSEHeader getHeader(String base64Header) { - try { - byte[] decodedHeader = Base64Url.decode(base64Header); - return JsonSerialization.readValue(decodedHeader, JWEHeader.class); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - - @Test - @UncaughtServerErrorExpected - public void testIdTokenEncryptionWithoutEncryptionKEK() throws Exception{ - ClientResource clientResource = null; - ClientRepresentation clientRep = null; - try { - // generate and register signing/verifying key onto client, not encryption key - TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints(); - oidcClientEndpointsResource.generateKeys(Algorithm.RS256); - - clientResource = AdminApiUtil.findClientByClientId(adminClient.realm("test"), "test-app"); - clientRep = clientResource.toRepresentation(); - // set id token signature algorithm and encryption algorithms - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenSignedResponseAlg(Algorithm.RS256); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseAlg(JWEConstants.RSA1_5); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseEnc(JWEConstants.A128CBC_HS256); - // use and set jwks_url - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setUseJwksUrl(true); - String jwksUrl = TestApplicationResourceUrls.clientJwksUri(); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setJwksUrl(jwksUrl); - clientResource.update(clientRep); - - // get id token but failed - AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password"); - AccessTokenResponse atr = oauth.doAccessTokenRequest(response.getCode()); - Assertions.assertEquals(OAuthErrorException.INVALID_REQUEST, atr.getError()); - Assertions.assertEquals("can not get encryption KEK", atr.getErrorDescription()); - - // get id token but failed with client_credentials grant type - oauth.scope("openid"); - AccessTokenResponse responseClientCredentials = oauth.client(clientRep.getClientId(), clientRep.getSecret()).doClientCredentialsGrantAccessTokenRequest(); - Assertions.assertEquals(OAuthErrorException.INVALID_REQUEST, responseClientCredentials.getError()); - Assertions.assertEquals("can not get encryption KEK", responseClientCredentials.getErrorDescription()); - } finally { - // Revert - clientResource = AdminApiUtil.findClientByClientId(adminClient.realm("test"), "test-app"); - clientRep = clientResource.toRepresentation(); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenSignedResponseAlg(Algorithm.RS256); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseAlg(null); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setIdTokenEncryptedResponseEnc(null); - // Revert jwks_url settings - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setUseJwksUrl(false); - OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRep).setJwksUrl(null); - clientResource.update(clientRep); - } - } - }