keycloak-uncached

Details

diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
index f29ed8c..152d632 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
@@ -66,6 +66,10 @@ import java.util.Map;
  */
 public class ClientAttributeCertificateResource {
 
+    public static final String CERTIFICATE_PEM = "Certificate PEM";
+    public static final String PUBLIC_KEY_PEM = "Public Key PEM";
+    public static final String JSON_WEB_KEY_SET = "JSON Web Key Set";
+
     protected RealmModel realm;
     private RealmAuth auth;
     protected ClientModel client;
@@ -195,12 +199,23 @@ public class ClientAttributeCertificateResource {
         Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
         String keystoreFormat = uploadForm.get("keystoreFormat").get(0).getBodyAsString();
         List<InputPart> inputParts = uploadForm.get("file");
-        if (keystoreFormat.equals("Certificate PEM")) {
+        if (keystoreFormat.equals(CERTIFICATE_PEM)) {
             String pem = StreamUtil.readString(inputParts.get(0).getBody(InputStream.class, null));
+
+            // Validate format
+            KeycloakModelUtils.getCertificate(pem);
+
             info.setCertificate(pem);
             return info;
+        } else if (keystoreFormat.equals(PUBLIC_KEY_PEM)) {
+            String pem = StreamUtil.readString(inputParts.get(0).getBody(InputStream.class, null));
+
+            // Validate format
+            KeycloakModelUtils.getPublicKey(pem);
 
-        } else if (keystoreFormat.equals("JSON Web Key Set (JWK)")) {
+            info.setPublicKey(pem);
+            return info;
+        } else if (keystoreFormat.equals(JSON_WEB_KEY_SET)) {
             InputStream stream = inputParts.get(0).getBody(InputStream.class, null);
             JSONWebKeySet keySet = JsonSerialization.readValue(stream, JSONWebKeySet.class);
             PublicKey publicKey = JWKSUtils.getKeyForUse(keySet, JWK.Use.SIG);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
index 087a1e6..c1cbdea 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
@@ -55,7 +55,9 @@ import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.util.CertificateInfoHelper;
 import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.auth.page.AuthRealm;
@@ -70,6 +72,7 @@ import java.net.URL;
 import java.nio.file.Files;
 import java.security.KeyStore;
 import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.cert.X509Certificate;
 import java.util.*;
 
@@ -81,7 +84,6 @@ import static org.junit.Assert.assertNotEquals;
  * @author Vaclav Muzikar <vmuzikar@redhat.com>
  */
 public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
-    public static final String CERTIFICATE_PEM = "Certificate PEM";
 
     @Rule
     public AssertEvents events = new AssertEvents(this);
@@ -349,8 +351,18 @@ public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
     }
 
     @Test
-    public void testUploadPEM() throws Exception {
-        testUploadKeystore(CERTIFICATE_PEM, "client-auth-test/certificate.pem", "undefined", "undefined");
+    public void testUploadCertificatePEM() throws Exception {
+        testUploadKeystore(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.CERTIFICATE_PEM, "client-auth-test/certificate.pem", "undefined", "undefined");
+    }
+
+    @Test
+    public void testUploadPublicKeyPEM() throws Exception {
+        testUploadKeystore(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.PUBLIC_KEY_PEM, "client-auth-test/publickey.pem", "undefined", "undefined");
+    }
+
+    @Test
+    public void testUploadJWKS() throws Exception {
+        testUploadKeystore(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.JSON_WEB_KEY_SET, "clientreg-test/jwks.json", "undefined", "undefined");
     }
 
     // We need to test this as a genuine REST API HTTP request
@@ -395,20 +407,27 @@ public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
         assertEquals(200, httpResponse.getStatusLine().getStatusCode());
 
         client = getClient(testRealm.getRealm(), client.getId()).toRepresentation();
-        String pem;
 
         // Assert the uploaded certificate
-        if (!keystoreFormat.equals(CERTIFICATE_PEM)) {
+        if (keystoreFormat.equals(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.PUBLIC_KEY_PEM)) {
+            String pem = new String(Files.readAllBytes(keystoreFile.toPath()));
+            final String publicKeyNew = client.getAttributes().get(JWTClientAuthenticator.ATTR_PREFIX + "." + CertificateInfoHelper.PUBLIC_KEY);
+            assertEquals("Certificates don't match", pem, publicKeyNew);
+        } else if (keystoreFormat.equals(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.JSON_WEB_KEY_SET)) {
+            final String publicKeyNew = client.getAttributes().get(JWTClientAuthenticator.ATTR_PREFIX + "." + CertificateInfoHelper.PUBLIC_KEY);
+            // Just assert it's valid public key
+            PublicKey pk = KeycloakModelUtils.getPublicKey(publicKeyNew);
+            Assert.assertNotNull(pk);
+        } else if (keystoreFormat.equals(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.CERTIFICATE_PEM)) {
+            String pem = new String(Files.readAllBytes(keystoreFile.toPath()));
+            assertCertificate(client, certOld, pem);
+        } else {
             InputStream keystoreIs = new FileInputStream(keystoreFile);
             KeyStore keyStore = getKeystore(keystoreIs, storePassword, keystoreFormat);
             keystoreIs.close();
-            pem = KeycloakModelUtils.getPemFromCertificate((X509Certificate) keyStore.getCertificate(keyAlias));
+            String pem = KeycloakModelUtils.getPemFromCertificate((X509Certificate) keyStore.getCertificate(keyAlias));
+            assertCertificate(client, certOld, pem);
         }
-        else {
-            pem = new String(Files.readAllBytes(keystoreFile.toPath()));
-        }
-
-        assertCertificate(client, certOld, pem);
     }
 
     // TEST ERRORS
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/certificate.pem b/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/certificate.pem
index 4c589e8..a526c93 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/certificate.pem
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/certificate.pem
@@ -1,13 +1,21 @@
-MIICWwIBAAKBgQCqXOsp76WfwXSNCU5AOix6SDhNR7MOdEtawJRmdUcBuJd/QeFh
-usLVOwm3a7s1134nlVKBEhOYBzKOY6LulvGDT4wHZUxE6cGJW+dEUd/6jrfZz9Ka
-XyATzLUn2BKBQZqRleQPKupwaOGQqQGQ4OmJrWKqG77Rb5O7GLNNDRCGpwIDAQAB
-AoGAA4sJLQcZ57erR9+gq/9Ju4VS/nB2Td+nTYzhyTu5LVT8eZ4SJOkwciTXL+Ri
-sVz497PIUnzgwXGs4H87/UBQZ4UJNz+kTC3L6nr4b5bWoIxoiY76R+gzlYiNEV9s
-QsX+K1FNKKMnEVa7t3DvbCFdlmt+4Agh/KQCU92Q13mj+WECQQDRF+BY1emtFfVC
-2miuSWorMLoaKv5At3BMgcs4KPzlfpMiEOMM/m1jmGrqUm40RZlnkhKEqQB0VeqF
-27gMGZuxAkEA0JTHqZDfcf5bBYhWzE3+Ec9A22/ZQgCiuV+DmWhCYxHLFsOYPkhT
-0jAibfJc8E8VchXMjeDktBAyotylQO1V1wJAcZisLPdCdeOpFMH9/zopcP+PC+px
-qY0/eIFHe+JgyvnCS86q3ANaQLKs21MfRkzNtAQbBXGfqpSGzmR5kDFVcQJAX1YR
-qMSKDS2IZw/5NGrVnUhQybvm3s8xkW9B1GWeKnAglqgSNy2R+nl70ys7Ja/QCpRC
-KftILbFVo7Eca3/PgwJAM5xMmg3Yx/WKkiCREvKXIGKOKN5rGWhHoLnYJHlsOi1r
-Z7Bef90rMp2kDrfLUAgrIJH06kxB+3oPRcmgjWlmDQ==
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIJAIzE3vQp7EQWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTYwMjI5MDgzMDU0WhcNNDMwNzE2MDgzMDU0WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAp1+GzdEkt2FZbISXYO12503FL6Oh8s4+tJ2fE66N8IezhugP8xiySDfW
+TEMaO5Z2TaTnQQoF9SSZ9Edq1GPxpBX0cdkCOBopEGdlb3hUYDeMaDMs18KGemUc
+Fj+CWB5VVcbmWMJ36WCz7FC+Oe38tmujR1AJpJL3pwqazyWIZzPqX8rW+rrNPGKP
+C96oBPZMb4RJWivLBJi/o5MGSpo1sJNtxyF4zUUI00LX0wZAV1HH1XErd1Vz41on
+nmB+tj9nevVRR4rDV280IELp9Ud0PIb3w843uJtwfSAwVG0pT6hv1VBDrBxTS08N
+dPU8CtkQAXzCCr8nqfAbUFOhcWRQgQIDAQABo1AwTjAdBgNVHQ4EFgQUFE+uUZAI
+n57ArEylqhCmHkAenTEwHwYDVR0jBBgwFoAUFE+uUZAIn57ArEylqhCmHkAenTEw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEApkgD3OCtw3+sk7GR1YaJ
+xNd8HT+fxXmnLqGnCQWX8lRIg5vj1PDMRev6vlIK3JfQV3zajcpKFfpy96klWsJy
+ZLYBVW2QOtMzDdQ9I8dS4Pn/SJ/Vo/M/ucfY4ttcuUL3oQCrI/c/u9tcamGMfbwd
+658MlXrUvt4B6qXY5AbgUvYR25P86uw7hSFMq5tQftNQsLbOh2FEeIiKhpgI7w8S
+SPajaWjUXsfHc5H7f9MciE2NS1Vd3AViGrVWP1rgQ1Iv0UyQVQrnjmIs12ENJmTd
+5lDqra5FJhaO7+RUG6er8n8HwXzhHkPmezGqtxWKikjitqvDY9prB3omJSa4Led+
+AQ==
+-----END CERTIFICATE-----
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/publickey.pem b/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/publickey.pem
index 906ff55..3169a04 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/publickey.pem
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/publickey.pem
@@ -1 +1,9 @@
-MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApnZ/E2BUULHjsRiSnEgZ
+4vGe15BRqZPdkHR+NcvVYpThc7JqY6nZrdrwO9sOjlMC5e2Q18Fypi4KbJpGSe9r
+0DPgcbPsHSoe2xFO3M8XBE0DyoRblaQFhe6p/sj3ak32k2zn+fMZUmlx/MTNQh1I
+Cki7So0NDCBXt8XGZNnEyvKeXOUZP5qicP9KxVAQiWJvlkaTjc8rrRTmf+HWw/Qf
+gQC0tzBRpa7T+RpW9O+rnWfOaNfTkTb9itIc+ZOa2Z4iidZ7+ifMOp9cNT641Wb6
+iYqJ2ufqY+msxI54tYM1tPgGS7r4SnCwmnqTaO383wXUl8TQ7qStmAWIepV3nNyu
+AQIDAQAB
+-----END PUBLIC KEY-----
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index d1041c7..acbe6ec 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -365,11 +365,12 @@ module.controller('ClientCertificateImportCtrl', function($scope, $location, $ht
     ];
 
     if (callingContext == 'jwt-credentials') {
-        $scope.keyFormats.push('JSON Web Key Set (JWK)');
+        $scope.keyFormats.push('Public Key PEM');
+        $scope.keyFormats.push('JSON Web Key Set');
     }
 
     $scope.hideKeystoreSettings = function() {
-        return $scope.uploadKeyFormat == 'Certificate PEM' || $scope.uploadKeyFormat == 'JSON Web Key Set (JWK)';
+        return $scope.uploadKeyFormat == 'Certificate PEM' || $scope.uploadKeyFormat == 'Public Key PEM' || $scope.uploadKeyFormat == 'JSON Web Key Set';
     }
 
     $scope.uploadKeyFormat = $scope.keyFormats[0];