keycloak-uncached
Changes
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java 181(+181 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java 54(+54 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaGeneratedKeyProviderTest.java 203(+203 -0)
Details
diff --git a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
index 07e91a4..d7fa875 100644
--- a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
@@ -53,10 +53,8 @@ public class JavaKeystoreKeyProvider extends AbstractRsaKeyProvider {
KeyPair keyPair = new KeyPair(publicKey, privateKey);
- X509Certificate certificate;
- if (model.contains(JavaKeystoreKeyProviderFactory.CERTIFICATE_ALIAS_KEY)) {
- certificate = (X509Certificate) keyStore.getCertificate(model.get(JavaKeystoreKeyProviderFactory.CERTIFICATE_ALIAS_KEY));
- } else {
+ X509Certificate certificate = (X509Certificate) keyStore.getCertificate(model.get(JavaKeystoreKeyProviderFactory.KEY_ALIAS_KEY));
+ if (certificate == null) {
certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, realm.getName());
}
diff --git a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
index 6b6e530..0691607 100644
--- a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
@@ -48,9 +48,6 @@ public class JavaKeystoreKeyProviderFactory extends AbstractRsaKeyProviderFactor
public static String KEY_PASSWORD_KEY = "keyPassword";
public static ProviderConfigProperty KEY_PASSWORD_PROPERTY = new ProviderConfigProperty(KEY_PASSWORD_KEY, "Private Key password", "Password for the private key", STRING_TYPE, null, true);
- public static String CERTIFICATE_ALIAS_KEY = "certificateAlias";
- public static ProviderConfigProperty CERTIFICATE_ALIAS_PROPERTY = new ProviderConfigProperty(CERTIFICATE_ALIAS_KEY, "Certificate Alias", "Alias for the certificate", STRING_TYPE, null);
-
private static final String HELP_TEXT = "Loads keys from a Java keys file";
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = AbstractRsaKeyProviderFactory.configurationBuilder()
@@ -58,7 +55,6 @@ public class JavaKeystoreKeyProviderFactory extends AbstractRsaKeyProviderFactor
.property(KEYSTORE_PASSWORD_PROPERTY)
.property(KEY_ALIAS_PROPERTY)
.property(KEY_PASSWORD_PROPERTY)
- .property(CERTIFICATE_ALIAS_PROPERTY)
.build();
@Override
@@ -74,8 +70,7 @@ public class JavaKeystoreKeyProviderFactory extends AbstractRsaKeyProviderFactor
.checkSingle(KEYSTORE_PROPERTY, true)
.checkSingle(KEYSTORE_PASSWORD_PROPERTY, true)
.checkSingle(KEY_ALIAS_PROPERTY, true)
- .checkSingle(KEY_PASSWORD_PROPERTY, true)
- .checkSingle(CERTIFICATE_ALIAS_PROPERTY, false);
+ .checkSingle(KEY_PASSWORD_PROPERTY, true);
try {
new JavaKeystoreKeyProvider(session.getContext().getRealm(), model)
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java
new file mode 100644
index 0000000..cac8a27
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/JavaKeystoreKeyProviderTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.keys;
+
+import org.apache.commons.io.IOUtils;
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.keycloak.common.util.KeyUtils;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.common.util.PemUtils;
+import org.keycloak.keys.Attributes;
+import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
+import org.keycloak.keys.JavaKeystoreKeyProviderFactory;
+import org.keycloak.keys.KeyMetadata;
+import org.keycloak.keys.KeyProvider;
+import org.keycloak.keys.RsaKeyProviderFactory;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.ErrorRepresentation;
+import org.keycloak.representations.idm.KeysMetadataRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.security.KeyPair;
+import java.security.cert.Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.util.List;
+
+import static org.junit.Assert.*;
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class JavaKeystoreKeyProviderTest extends AbstractKeycloakTest {
+
+ private static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsPAJ/X39oNRkoS+baWVhAghfO86ZPfkSHm4evmMDhbA0KqW1/hg55qUJoT91ytGozIsIxoCLKzQvZTluRpt0AMp7cmfaGWBQ8cBtb8/BL+5FkUucigmOcTrfPq9/xR9g4AMSXRItjLRsJPy2Bnjau64DVQ3N5NVbWAMw7/1XjuobEyPnw0RLqEr/TxWMteuaiV1n8amIAiT91xZ8UFyPv3urCkAz+r+iyVvdJcZwn2tUL6KLM7qX/HSX8SUtPrIMB8EdW1yNt5McO8Ro5GxwiyXimDKbY9ur2WP8/wrdk/0TkoUYeI1UsnFyoJcqqg2+1T+dNAMtJhF7uDhURVQ33QIDAQAB";
+ private static final String CERTIFICATE = "MIIDeTCCAmGgAwIBAgIEbhSauDANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMCAXDTE2MTAxMzE4MjUxNFoYDzIyOTAwNzI4MTgyNTE0WjBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsPAJ/X39oNRkoS+baWVhAghfO86ZPfkSHm4evmMDhbA0KqW1/hg55qUJoT91ytGozIsIxoCLKzQvZTluRpt0AMp7cmfaGWBQ8cBtb8/BL+5FkUucigmOcTrfPq9/xR9g4AMSXRItjLRsJPy2Bnjau64DVQ3N5NVbWAMw7/1XjuobEyPnw0RLqEr/TxWMteuaiV1n8amIAiT91xZ8UFyPv3urCkAz+r+iyVvdJcZwn2tUL6KLM7qX/HSX8SUtPrIMB8EdW1yNt5McO8Ro5GxwiyXimDKbY9ur2WP8/wrdk/0TkoUYeI1UsnFyoJcqqg2+1T+dNAMtJhF7uDhURVQ33QIDAQABoyEwHzAdBgNVHQ4EFgQUgz0ABmkImZUEO2/w0shoH4rp6pwwDQYJKoZIhvcNAQELBQADggEBAK+syjqfFXmv7942+ZfmJfb4i/JilhwSyA2G1VvGR39dLW1nPmKMMUY6kKgJ2NZgaCGvJ4jxDhfNJ1jPG7rcO/eQuF3cx9r+nHiTcJ5PNLqG2q4dNNFshJ8aGuIaTQEB7S1OlGsEj0rd0YlJ+LTrFfEHsnsJvpvDRLdVMklib5fPk4W8ziuQ3rr6T/a+be3zfAqmFZx8j6E46jz9QO841uwqdzcR9kfSHS/76TNGZv8OB6jheyHrUdBygR85iizHgMqats/0zWmKEAvSp/DhAfyIFp8zZHvPjmpBl+mfmAqnrYY0oJRb5rRXmL8DKq5plc7jgO1H6aHh5mV6slXQDEw=";
+
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ @Rule
+ public AssertEvents events = new AssertEvents(this);
+
+ @Page
+ protected AppPage appPage;
+
+ @Page
+ protected LoginPage loginPage;
+ private File file;
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ RealmRepresentation realm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+ testRealms.add(realm);
+ }
+
+ @Override
+ public void beforeAbstractKeycloakTest() throws Exception {
+ super.beforeAbstractKeycloakTest();
+
+ file = folder.newFile("keystore.jsk");
+
+ InputStream resourceAsStream = JavaKeystoreKeyProviderTest.class.getResourceAsStream("keystore.jks");
+ IOUtils.copy(resourceAsStream, new FileOutputStream(file));
+ }
+
+ @Test
+ public void create() throws Exception {
+ long priority = System.currentTimeMillis();
+
+ ComponentRepresentation rep = createRep("valid", priority);
+
+ Response response = adminClient.realm("test").components().add(rep);
+ String id = ApiUtil.getCreatedId(response);
+
+ ComponentRepresentation createdRep = adminClient.realm("test").components().component(id).toRepresentation();
+ assertEquals(5, createdRep.getConfig().size());
+ assertEquals(Long.toString(priority), createdRep.getConfig().getFirst("priority"));
+ assertEquals(ComponentRepresentation.SECRET_VALUE, createdRep.getConfig().getFirst("keystorePassword"));
+ assertEquals(ComponentRepresentation.SECRET_VALUE, createdRep.getConfig().getFirst("keyPassword"));
+
+ KeysMetadataRepresentation keys = adminClient.realm("test").keys().getKeyMetadata();
+
+ KeysMetadataRepresentation.KeyMetadataRepresentation key = keys.getKeys().get(0);
+
+ assertEquals(id, key.getProviderId());
+ assertEquals(KeyMetadata.Type.RSA.name(), key.getType());
+ assertEquals(priority, key.getProviderPriority());
+ assertEquals(PUBLIC_KEY, key.getPublicKey());
+ assertEquals(CERTIFICATE, key.getCertificate());
+ }
+
+ @Test
+ public void invalidKeystore() throws Exception {
+ ComponentRepresentation rep = createRep("valid", System.currentTimeMillis());
+ rep.getConfig().putSingle("keystore", "/nosuchfile");
+
+ Response response = adminClient.realm("test").components().add(rep);
+ assertErrror(response, "Failed to load keys");
+ }
+
+ @Test
+ public void invalidKeystorePassword() throws Exception {
+ ComponentRepresentation rep = createRep("valid", System.currentTimeMillis());
+ rep.getConfig().putSingle("keystore", "invalid");
+
+ Response response = adminClient.realm("test").components().add(rep);
+ assertErrror(response, "Failed to load keys");
+ }
+
+ @Test
+ public void invalidKeyAlias() throws Exception {
+ ComponentRepresentation rep = createRep("valid", System.currentTimeMillis());
+ rep.getConfig().putSingle("keyAlias", "invalid");
+
+ Response response = adminClient.realm("test").components().add(rep);
+ assertErrror(response, "Failed to load keys");
+ }
+
+ @Test
+ public void invalidKeyPassword() throws Exception {
+ ComponentRepresentation rep = createRep("valid", System.currentTimeMillis());
+ rep.getConfig().putSingle("keyPassword", "invalid");
+
+ Response response = adminClient.realm("test").components().add(rep);
+ assertErrror(response, "Failed to load keys");
+ }
+
+ protected void assertErrror(Response response, String error) {
+ if (!response.hasEntity()) {
+ fail("No error message set");
+ }
+
+ ErrorRepresentation errorRepresentation = response.readEntity(ErrorRepresentation.class);
+ assertEquals(error, errorRepresentation.getErrorMessage());
+ }
+
+ protected ComponentRepresentation createRep(String name, long priority) {
+ ComponentRepresentation rep = new ComponentRepresentation();
+ rep.setName(name);
+ rep.setParentId("test");
+ rep.setProviderId(JavaKeystoreKeyProviderFactory.ID);
+ rep.setProviderType(KeyProvider.class.getName());
+ rep.setConfig(new MultivaluedHashMap<>());
+ rep.getConfig().putSingle("priority", Long.toString(priority));
+ rep.getConfig().putSingle("keystore", file.getAbsolutePath());
+ rep.getConfig().putSingle("keystorePassword", "password");
+ rep.getConfig().putSingle("keyAlias", "selfsigned");
+ rep.getConfig().putSingle("keyPassword", "password");
+ return rep;
+ }
+
+}
+
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java
index fd4fdfe..964832c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/KeyRotationTest.java
@@ -17,6 +17,8 @@
package org.keycloak.testsuite.keys;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Rule;
import org.junit.Test;
@@ -28,6 +30,8 @@ import org.keycloak.common.util.PemUtils;
import org.keycloak.keys.Attributes;
import org.keycloak.keys.KeyProvider;
import org.keycloak.keys.RsaKeyProviderFactory;
+import org.keycloak.representations.UserInfo;
+import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
@@ -37,9 +41,13 @@ import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.util.KeycloakModelUtils;
import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.testsuite.util.UserInfoClientUtil;
+import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
+import java.io.IOException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.List;
@@ -65,6 +73,10 @@ public class KeyRotationTest extends AbstractKeycloakTest {
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation realm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
testRealms.add(realm);
+
+ ClientRepresentation confApp = KeycloakModelUtils.createClient(realm, "confidential-cli");
+ confApp.setSecret("secret1");
+ confApp.setServiceAccountsEnabled(Boolean.TRUE);
}
@Test
@@ -114,6 +126,12 @@ public class KeyRotationTest extends AbstractKeycloakTest {
assertTokenSignature(key1, response.getAccessToken());
assertTokenSignature(key1, response.getRefreshToken());
+ // Userinfo with keys #1
+ assertUserInfo(response.getAccessToken(), 200);
+
+ // Token introspection with keys #1
+ assertTokenIntrospection(response.getAccessToken(), true);
+
// Create keys #2
PublicKey key2 = createKeys2();
@@ -123,6 +141,12 @@ public class KeyRotationTest extends AbstractKeycloakTest {
assertTokenSignature(key2, response.getAccessToken());
assertTokenSignature(key2, response.getRefreshToken());
+ // Userinfo with keys #2
+ assertUserInfo(response.getAccessToken(), 200);
+
+ // Token introspection with keys #2
+ assertTokenIntrospection(response.getAccessToken(), true);
+
// Drop key #1
dropKeys1();
@@ -131,9 +155,21 @@ public class KeyRotationTest extends AbstractKeycloakTest {
assertTokenSignature(key2, response.getAccessToken());
assertTokenSignature(key2, response.getRefreshToken());
+ // Userinfo with keys #1 dropped
+ assertUserInfo(response.getAccessToken(), 200);
+
+ // Token introspection with keys #1 dropped
+ assertTokenIntrospection(response.getAccessToken(), true);
+
// Drop key #2
dropKeys2();
+ // Userinfo with keys #2 dropped
+ assertUserInfo(response.getAccessToken(), 401);
+
+ // Token introspection with keys #2 dropped
+ assertTokenIntrospection(response.getAccessToken(), false);
+
// Refresh token with keys #2 dropped - should fail as refresh token is signed with key #2
response = oauth.doRefreshTokenRequest(response.getRefreshToken(), "password");
assertEquals(400, response.getStatusCode());
@@ -232,5 +268,23 @@ public class KeyRotationTest extends AbstractKeycloakTest {
throw new RuntimeException("Failed to find keys1");
}
+ private void assertUserInfo(String token, int expectedStatus) {
+ Response userInfoResponse = UserInfoClientUtil.executeUserInfoRequest_getMethod(ClientBuilder.newClient(), token);
+ assertEquals(expectedStatus, userInfoResponse.getStatus());
+ userInfoResponse.close();
+ }
+
+ private void assertTokenIntrospection(String token, boolean expectActive) {
+ try {
+ String tokenResponse = oauth.introspectAccessTokenWithClientCredential("confidential-cli", "secret1", token);
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(tokenResponse);
+ assertEquals(expectActive, jsonNode.get("active").asBoolean());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaGeneratedKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaGeneratedKeyProviderTest.java
new file mode 100644
index 0000000..324d999
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaGeneratedKeyProviderTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.keys;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.common.util.PemUtils;
+import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
+import org.keycloak.keys.KeyMetadata;
+import org.keycloak.keys.KeyProvider;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.ErrorRepresentation;
+import org.keycloak.representations.idm.KeysMetadataRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+
+import javax.ws.rs.core.Response;
+import java.security.interfaces.RSAPublicKey;
+import java.util.List;
+
+import static org.junit.Assert.*;
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RsaGeneratedKeyProviderTest extends AbstractKeycloakTest {
+
+ @Rule
+ public AssertEvents events = new AssertEvents(this);
+
+ @Page
+ protected AppPage appPage;
+
+ @Page
+ protected LoginPage loginPage;
+
+ @Override
+ public void addTestRealms(List<RealmRepresentation> testRealms) {
+ RealmRepresentation realm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+ testRealms.add(realm);
+ }
+
+ @Test
+ public void defaultKeysize() throws Exception {
+ long priority = System.currentTimeMillis();
+
+ ComponentRepresentation rep = createRep("valid", GeneratedRsaKeyProviderFactory.ID);
+ rep.setConfig(new MultivaluedHashMap<>());
+ rep.getConfig().putSingle("priority", Long.toString(priority));
+
+ Response response = adminClient.realm("test").components().add(rep);
+ String id = ApiUtil.getCreatedId(response);
+
+ ComponentRepresentation createdRep = adminClient.realm("test").components().component(id).toRepresentation();
+ assertEquals(2, createdRep.getConfig().size());
+ assertEquals(Long.toString(priority), createdRep.getConfig().getFirst("priority"));
+ assertEquals("2048", createdRep.getConfig().getFirst("keySize"));
+
+ KeysMetadataRepresentation keys = adminClient.realm("test").keys().getKeyMetadata();
+
+ KeysMetadataRepresentation.KeyMetadataRepresentation key = keys.getKeys().get(0);
+
+ assertEquals(id, key.getProviderId());
+ assertEquals(KeyMetadata.Type.RSA.name(), key.getType());
+ assertEquals(priority, key.getProviderPriority());
+ assertEquals(2048, ((RSAPublicKey) PemUtils.decodePublicKey(keys.getKeys().get(0).getPublicKey())).getModulus().bitLength());
+ }
+
+ @Test
+ public void largeKeysize() throws Exception {
+ long priority = System.currentTimeMillis();
+
+ ComponentRepresentation rep = createRep("valid", GeneratedRsaKeyProviderFactory.ID);
+ rep.setConfig(new MultivaluedHashMap<>());
+ rep.getConfig().putSingle("priority", Long.toString(priority));
+ rep.getConfig().putSingle("keySize", "4096");
+
+ Response response = adminClient.realm("test").components().add(rep);
+ String id = ApiUtil.getCreatedId(response);
+
+ ComponentRepresentation createdRep = adminClient.realm("test").components().component(id).toRepresentation();
+ assertEquals(2, createdRep.getConfig().size());
+ assertEquals("4096", createdRep.getConfig().getFirst("keySize"));
+
+ KeysMetadataRepresentation keys = adminClient.realm("test").keys().getKeyMetadata();
+
+ KeysMetadataRepresentation.KeyMetadataRepresentation key = keys.getKeys().get(0);
+
+ assertEquals(id, key.getProviderId());
+ assertEquals(KeyMetadata.Type.RSA.name(), key.getType());
+ assertEquals(priority, key.getProviderPriority());
+ assertEquals(4096, ((RSAPublicKey) PemUtils.decodePublicKey(keys.getKeys().get(0).getPublicKey())).getModulus().bitLength());
+ }
+
+ @Test
+ public void updatePriority() throws Exception {
+ long priority = System.currentTimeMillis();
+
+ ComponentRepresentation rep = createRep("valid", GeneratedRsaKeyProviderFactory.ID);
+ rep.setConfig(new MultivaluedHashMap<>());
+ rep.getConfig().putSingle("priority", Long.toString(priority));
+
+ Response response = adminClient.realm("test").components().add(rep);
+ String id = ApiUtil.getCreatedId(response);
+
+ KeysMetadataRepresentation keys = adminClient.realm("test").keys().getKeyMetadata();
+
+ String publicKey = keys.getKeys().get(0).getPublicKey();
+
+ ComponentRepresentation createdRep = adminClient.realm("test").components().component(id).toRepresentation();
+
+ priority += 1000;
+
+ createdRep.getConfig().putSingle("priority", Long.toString(priority));
+ adminClient.realm("test").components().component(id).update(createdRep);
+
+ keys = adminClient.realm("test").keys().getKeyMetadata();
+
+ String publicKey2 = keys.getKeys().get(0).getPublicKey();
+
+ assertEquals(publicKey, publicKey2);
+ }
+
+ @Test
+ public void updateKeysize() throws Exception {
+ long priority = System.currentTimeMillis();
+
+ ComponentRepresentation rep = createRep("valid", GeneratedRsaKeyProviderFactory.ID);
+ rep.setConfig(new MultivaluedHashMap<>());
+ rep.getConfig().putSingle("priority", Long.toString(priority));
+
+ Response response = adminClient.realm("test").components().add(rep);
+ String id = ApiUtil.getCreatedId(response);
+
+ KeysMetadataRepresentation keys = adminClient.realm("test").keys().getKeyMetadata();
+
+ String publicKey = keys.getKeys().get(0).getPublicKey();
+
+ ComponentRepresentation createdRep = adminClient.realm("test").components().component(id).toRepresentation();
+ createdRep.getConfig().putSingle("keySize", "4096");
+ adminClient.realm("test").components().component(id).update(createdRep);
+
+ keys = adminClient.realm("test").keys().getKeyMetadata();
+
+ String publicKey2 = keys.getKeys().get(0).getPublicKey();
+
+ assertNotEquals(publicKey, publicKey2);
+ assertEquals(2048, ((RSAPublicKey) PemUtils.decodePublicKey(publicKey)).getModulus().bitLength());
+ assertEquals(4096, ((RSAPublicKey) PemUtils.decodePublicKey(publicKey2)).getModulus().bitLength());
+ }
+
+ @Test
+ public void invalidKeysize() throws Exception {
+ ComponentRepresentation rep = createRep("invalid", GeneratedRsaKeyProviderFactory.ID);
+ rep.getConfig().putSingle("keySize", "1234");
+
+ Response response = adminClient.realm("test").components().add(rep);
+ assertErrror(response, "Keysize should be 1024, 2048 or 4096");
+ }
+
+ protected void assertErrror(Response response, String error) {
+ if (!response.hasEntity()) {
+ fail("No error message set");
+ }
+
+ ErrorRepresentation errorRepresentation = response.readEntity(ErrorRepresentation.class);
+ assertEquals(error, errorRepresentation.getErrorMessage());
+ }
+
+ protected ComponentRepresentation createRep(String name, String providerId) {
+ ComponentRepresentation rep = new ComponentRepresentation();
+ rep.setName(name);
+ rep.setParentId("test");
+ rep.setProviderId(providerId);
+ rep.setProviderType(KeyProvider.class.getName());
+ rep.setConfig(new MultivaluedHashMap<>());
+ return rep;
+ }
+
+}
+
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java
index 649c662..65cda1a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/RsaKeyProviderTest.java
@@ -27,6 +27,7 @@ import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.PemUtils;
import org.keycloak.keys.Attributes;
+import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
import org.keycloak.keys.KeyMetadata;
import org.keycloak.keys.KeyProvider;
import org.keycloak.keys.RsaKeyProvider;
@@ -76,12 +77,14 @@ public class RsaKeyProviderTest extends AbstractKeycloakTest {
@Test
public void privateKeyOnly() throws Exception {
+ long priority = System.currentTimeMillis();
+
KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
String kid = KeyUtils.createKeyId(keyPair.getPublic());
ComponentRepresentation rep = createRep("valid", RsaKeyProviderFactory.ID);
rep.getConfig().putSingle(Attributes.PRIVATE_KEY_KEY, PemUtils.encodeKey(keyPair.getPrivate()));
- rep.getConfig().putSingle(Attributes.PRIORITY_KEY, "1000");
+ rep.getConfig().putSingle(Attributes.PRIORITY_KEY, Long.toString(priority));
Response response = adminClient.realm("test").components().add(rep);
String id = ApiUtil.getCreatedId(response);
@@ -100,7 +103,7 @@ public class RsaKeyProviderTest extends AbstractKeycloakTest {
assertEquals(id, key.getProviderId());
assertEquals(KeyMetadata.Type.RSA.name(), key.getType());
- assertEquals(1000l, key.getProviderPriority());
+ assertEquals(priority, key.getProviderPriority());
assertEquals(kid, key.getKid());
assertEquals(PemUtils.encodeKey(keyPair.getPublic()), keys.getKeys().get(0).getPublicKey());
assertEquals(keyPair.getPublic(), PemUtils.decodeCertificate(key.getCertificate()).getPublicKey());
@@ -108,6 +111,8 @@ public class RsaKeyProviderTest extends AbstractKeycloakTest {
@Test
public void keyAndCertificate() throws Exception {
+ long priority = System.currentTimeMillis();
+
KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, "test");
String certificatePem = PemUtils.encodeCertificate(certificate);
@@ -115,7 +120,7 @@ public class RsaKeyProviderTest extends AbstractKeycloakTest {
ComponentRepresentation rep = createRep("valid", RsaKeyProviderFactory.ID);
rep.getConfig().putSingle(Attributes.PRIVATE_KEY_KEY, PemUtils.encodeKey(keyPair.getPrivate()));
rep.getConfig().putSingle(Attributes.CERTIFICATE_KEY, certificatePem);
- rep.getConfig().putSingle(Attributes.PRIORITY_KEY, "1000");
+ rep.getConfig().putSingle(Attributes.PRIORITY_KEY, Long.toString(priority));
Response response = adminClient.realm("test").components().add(rep);
String id = ApiUtil.getCreatedId(response);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/keys/keystore.jks b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/keys/keystore.jks
new file mode 100644
index 0000000..ad54a7b
Binary files /dev/null and b/testsuite/integration-arquillian/tests/base/src/test/resources/org/keycloak/testsuite/keys/keystore.jks differ