Details
diff --git a/services/src/main/java/org/keycloak/keys/loader/HardcodedPublicKeyLoader.java b/services/src/main/java/org/keycloak/keys/loader/HardcodedPublicKeyLoader.java
new file mode 100644
index 0000000..b5cbbde
--- /dev/null
+++ b/services/src/main/java/org/keycloak/keys/loader/HardcodedPublicKeyLoader.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 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.keys.loader;
+
+import org.keycloak.common.util.PemUtils;
+import org.keycloak.keys.PublicKeyLoader;
+
+import java.security.PublicKey;
+import java.util.*;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class HardcodedPublicKeyLoader implements PublicKeyLoader {
+
+ private final String kid;
+ private final String pem;
+
+ public HardcodedPublicKeyLoader(String kid, String pem) {
+ this.kid = kid;
+ this.pem = pem;
+ }
+
+ @Override
+ public Map<String, PublicKey> loadKeys() throws Exception {
+ return Collections.unmodifiableMap(Collections.singletonMap(kid, getSavedPublicKey()));
+ }
+
+ protected PublicKey getSavedPublicKey() {
+ if (pem != null && ! pem.trim().equals("")) {
+ return PemUtils.decodePublicKey(pem);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/services/src/main/java/org/keycloak/keys/loader/PublicKeyStorageManager.java b/services/src/main/java/org/keycloak/keys/loader/PublicKeyStorageManager.java
index d4507e9..30aae3f 100644
--- a/services/src/main/java/org/keycloak/keys/loader/PublicKeyStorageManager.java
+++ b/services/src/main/java/org/keycloak/keys/loader/PublicKeyStorageManager.java
@@ -21,17 +21,20 @@ import java.security.PublicKey;
import org.keycloak.broker.oidc.OIDCIdentityProviderConfig;
import org.keycloak.jose.jws.JWSInput;
-import org.keycloak.keys.PublicKeyStorageProvider;
-import org.keycloak.keys.PublicKeyStorageUtils;
+import org.keycloak.keys.*;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import org.jboss.logging.Logger;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PublicKeyStorageManager {
+ private static final Logger logger = Logger.getLogger(PublicKeyStorageManager.class);
+
public static PublicKey getClientPublicKey(KeycloakSession session, ClientModel client, JWSInput input) {
String kid = input.getHeader().getKeyId();
@@ -44,13 +47,31 @@ public class PublicKeyStorageManager {
public static PublicKey getIdentityProviderPublicKey(KeycloakSession session, RealmModel realm, OIDCIdentityProviderConfig idpConfig, JWSInput input) {
+ boolean keyIdSetInConfiguration = idpConfig.getPublicKeySignatureVerifierKeyId() != null
+ && ! idpConfig.getPublicKeySignatureVerifierKeyId().trim().isEmpty();
+
String kid = input.getHeader().getKeyId();
PublicKeyStorageProvider keyStorage = session.getProvider(PublicKeyStorageProvider.class);
String modelKey = PublicKeyStorageUtils.getIdpModelCacheKey(realm.getId(), idpConfig.getInternalId());
- OIDCIdentityProviderPublicKeyLoader loader = new OIDCIdentityProviderPublicKeyLoader(session, idpConfig);
+ PublicKeyLoader loader;
+ if (idpConfig.isUseJwksUrl()) {
+ loader = new OIDCIdentityProviderPublicKeyLoader(session, idpConfig);
+ } else {
+ String pem = idpConfig.getPublicKeySignatureVerifier();
+
+ if (pem == null || pem.trim().isEmpty()) {
+ logger.warnf("No public key saved on identityProvider %s", idpConfig.getAlias());
+ return null;
+ }
+
+ loader = new HardcodedPublicKeyLoader(
+ keyIdSetInConfiguration
+ ? idpConfig.getPublicKeySignatureVerifierKeyId().trim()
+ : kid, pem);
+ }
+
return keyStorage.getPublicKey(modelKey, kid, loader);
}
-
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java
index 6bc60b1..e7d8d44 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java
@@ -211,6 +211,23 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest {
// Set key id to a valid one
cfg.setPublicKeySignatureVerifierKeyId(expectedKeyId);
updateIdentityProvider(idpRep);
+ logInAsUserInIDP();
+ assertLoggedInAccountManagement();
+ logoutFromRealm(bc.consumerRealmName());
+
+ // Set key id to empty
+ cfg.setPublicKeySignatureVerifierKeyId("");
+ updateIdentityProvider(idpRep);
+ logInAsUserInIDP();
+ assertLoggedInAccountManagement();
+ logoutFromRealm(bc.consumerRealmName());
+
+ // Unset key id
+ cfg.setPublicKeySignatureVerifierKeyId(null);
+ updateIdentityProvider(idpRep);
+ logInAsUserInIDP();
+ assertLoggedInAccountManagement();
+ logoutFromRealm(bc.consumerRealmName());
}
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index b6d285b..d047b77 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -504,7 +504,7 @@ identity-provider.jwks-url.tooltip=URL where identity provider keys in JWK forma
validating-public-key=Validating Public Key
identity-provider.validating-public-key.tooltip=The public key in PEM format that must be used to verify external IDP signatures.
validating-public-key-id=Validating Public Key Id
-identity-provider.validating-public-key-id.tooltip=Explicit ID of the validating public key given above if the key ID. Leave unset if the external IDP is Keycloak or uses the same mechanism to determine key ID.
+identity-provider.validating-public-key-id.tooltip=Explicit ID of the validating public key given above if the key ID. Leave blank if the key above should be used always, regardless of key ID specified by external IDP; set it if the key should only be used for verifying if key ID from external IDP matches.
import-external-idp-config=Import External IDP Config
import-external-idp-config.tooltip=Allows you to load external IDP metadata from a config file or to download it from a URL.
import-from-url=Import from URL