1
0
mirror of https://github.com/keycloak/keycloak.git synced 2026-10-23 19:29:23 +03:00

Migrate IdTokenEncryptionTest.java to the new test framework (#54269)

Closes #53289


Signed-off-by: Paddy Buckley <paddy.buckley@ibm.com>
This commit is contained in:
Paddy Buckley
2026-10-23 14:53:32 +01:00
committed by GitHub
parent 0486c6c92f
commit 333aee90d1
3 changed files with 171 additions and 250 deletions

View File

@@ -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;

View File

@@ -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));
}
}
}

View File

@@ -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<RealmRepresentation> 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<String, String> 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<String, String> 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);
}
}
}