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:
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user