keycloak-uncached

KEYCLOAK-905 More testing

10/13/2016 3:44:33 PM

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