keycloak-aplcache
Changes
services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java 10(+5 -5)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java 3(+2 -1)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java 12(+12 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java 3(+2 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java 4(+2 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOIDCBrokerWithSignatureTest.java 5(+3 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java 11(+7 -4)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java 10(+6 -4)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java 3(+2 -1)
Details
diff --git a/core/src/main/java/org/keycloak/crypto/JavaAlgorithm.java b/core/src/main/java/org/keycloak/crypto/JavaAlgorithm.java
new file mode 100644
index 0000000..46d084c
--- /dev/null
+++ b/core/src/main/java/org/keycloak/crypto/JavaAlgorithm.java
@@ -0,0 +1,42 @@
+/*
+ * 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.crypto;
+
+public class JavaAlgorithm {
+
+ public static String getJavaAlgorithm(String algorithm) {
+ switch (algorithm) {
+ case Algorithm.RS256:
+ return "SHA256withRSA";
+ case Algorithm.RS384:
+ return "SHA384withRSA";
+ case Algorithm.RS512:
+ return "SHA512withRSA";
+ case Algorithm.HS256:
+ return "HMACSHA256";
+ case Algorithm.HS384:
+ return "HMACSHA384";
+ case Algorithm.HS512:
+ return "HMACSHA512";
+ case Algorithm.AES:
+ return "AES";
+ default:
+ throw new IllegalArgumentException("Unkown algorithm " + algorithm);
+ }
+ }
+
+}
diff --git a/core/src/main/java/org/keycloak/crypto/KeyWrapper.java b/core/src/main/java/org/keycloak/crypto/KeyWrapper.java
new file mode 100644
index 0000000..2a592aa
--- /dev/null
+++ b/core/src/main/java/org/keycloak/crypto/KeyWrapper.java
@@ -0,0 +1,135 @@
+/*
+ * 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.crypto;
+
+import javax.crypto.SecretKey;
+import java.security.Key;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class KeyWrapper {
+
+ private String providerId;
+ private long providerPriority;
+ private String kid;
+ private Set<String> algorithms;
+ private String type;
+ private KeyUse use;
+ private KeyStatus status;
+ private SecretKey secretKey;
+ private Key signKey;
+ private Key verifyKey;
+ private X509Certificate certificate;
+
+ public String getProviderId() {
+ return providerId;
+ }
+
+ public void setProviderId(String providerId) {
+ this.providerId = providerId;
+ }
+
+ public long getProviderPriority() {
+ return providerPriority;
+ }
+
+ public void setProviderPriority(long providerPriority) {
+ this.providerPriority = providerPriority;
+ }
+
+ public String getKid() {
+ return kid;
+ }
+
+ public void setKid(String kid) {
+ this.kid = kid;
+ }
+
+ public Set<String> getAlgorithms() {
+ return algorithms;
+ }
+
+ public void setAlgorithms(String... algorithms) {
+ this.algorithms = new HashSet<>();
+ for (String a : algorithms) {
+ this.algorithms.add(a);
+ }
+ }
+
+ public void setAlgorithms(Set<String> algorithms) {
+ this.algorithms = algorithms;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public KeyUse getUse() {
+ return use;
+ }
+
+ public void setUse(KeyUse use) {
+ this.use = use;
+ }
+
+ public KeyStatus getStatus() {
+ return status;
+ }
+
+ public void setStatus(KeyStatus status) {
+ this.status = status;
+ }
+
+ public SecretKey getSecretKey() {
+ return secretKey;
+ }
+
+ public void setSecretKey(SecretKey secretKey) {
+ this.secretKey = secretKey;
+ }
+
+ public Key getSignKey() {
+ return signKey;
+ }
+
+ public void setSignKey(Key signKey) {
+ this.signKey = signKey;
+ }
+
+ public Key getVerifyKey() {
+ return verifyKey;
+ }
+
+ public void setVerifyKey(Key verifyKey) {
+ this.verifyKey = verifyKey;
+ }
+
+ public X509Certificate getCertificate() {
+ return certificate;
+ }
+
+ public void setCertificate(X509Certificate certificate) {
+ this.certificate = certificate;
+ }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java
index 54d3ba9..e70c273 100644
--- a/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/KeysMetadataRepresentation.java
@@ -19,6 +19,7 @@ package org.keycloak.representations.idm;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -54,6 +55,7 @@ public class KeysMetadataRepresentation {
private String status;
private String type;
+ private Set<String> algorithms;
private String publicKey;
private String certificate;
@@ -98,6 +100,14 @@ public class KeysMetadataRepresentation {
this.type = type;
}
+ public Set<String> getAlgorithms() {
+ return algorithms;
+ }
+
+ public void setAlgorithms(Set<String> algorithms) {
+ this.algorithms = algorithms;
+ }
+
public String getPublicKey() {
return publicKey;
}
diff --git a/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java b/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java
index c9adebd..296a413 100644
--- a/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java
+++ b/server-spi/src/main/java/org/keycloak/keys/KeyMetadata.java
@@ -17,21 +17,19 @@
package org.keycloak.keys;
+import org.keycloak.crypto.KeyStatus;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public abstract class KeyMetadata {
- public enum Status {
- ACTIVE, PASSIVE, DISABLED
- }
-
private String providerId;
private long providerPriority;
private String kid;
- private Status status;
+ private KeyStatus status;
public String getProviderId() {
return providerId;
@@ -57,11 +55,11 @@ public abstract class KeyMetadata {
this.kid = kid;
}
- public Status getStatus() {
+ public KeyStatus getStatus() {
return status;
}
- public void setStatus(Status status) {
+ public void setStatus(KeyStatus status) {
this.status = status;
}
diff --git a/server-spi/src/main/java/org/keycloak/models/KeyManager.java b/server-spi/src/main/java/org/keycloak/models/KeyManager.java
index bc47dcb..f7a9b40 100644
--- a/server-spi/src/main/java/org/keycloak/models/KeyManager.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeyManager.java
@@ -17,6 +17,8 @@
package org.keycloak.models;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.keys.SecretKeyMetadata;
import org.keycloak.keys.RsaKeyMetadata;
@@ -32,25 +34,43 @@ import java.util.List;
*/
public interface KeyManager {
+ KeyWrapper getActiveKey(RealmModel realm, KeyUse use, String algorithm);
+
+ KeyWrapper getKey(RealmModel realm, String kid, KeyUse use, String algorithm);
+
+ List<KeyWrapper> getKeys(RealmModel realm);
+
+ List<KeyWrapper> getKeys(RealmModel realm, KeyUse use, String algorithm);
+
+ @Deprecated
ActiveRsaKey getActiveRsaKey(RealmModel realm);
+ @Deprecated
PublicKey getRsaPublicKey(RealmModel realm, String kid);
+ @Deprecated
Certificate getRsaCertificate(RealmModel realm, String kid);
- List<RsaKeyMetadata> getRsaKeys(RealmModel realm, boolean includeDisabled);
+ @Deprecated
+ List<RsaKeyMetadata> getRsaKeys(RealmModel realm);
+ @Deprecated
ActiveHmacKey getActiveHmacKey(RealmModel realm);
+ @Deprecated
SecretKey getHmacSecretKey(RealmModel realm, String kid);
- List<SecretKeyMetadata> getHmacKeys(RealmModel realm, boolean includeDisabled);
+ @Deprecated
+ List<SecretKeyMetadata> getHmacKeys(RealmModel realm);
+ @Deprecated
ActiveAesKey getActiveAesKey(RealmModel realm);
+ @Deprecated
SecretKey getAesSecretKey(RealmModel realm, String kid);
- List<SecretKeyMetadata> getAesKeys(RealmModel realm, boolean includeDisabled);
+ @Deprecated
+ List<SecretKeyMetadata> getAesKeys(RealmModel realm);
class ActiveRsaKey {
private final String kid;
diff --git a/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java b/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java
index fb9e152..7984ea6 100644
--- a/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/keys/KeyProvider.java
@@ -17,6 +17,7 @@
package org.keycloak.keys;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.jose.jws.AlgorithmType;
import org.keycloak.provider.Provider;
@@ -28,26 +29,15 @@ import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public interface KeyProvider<T extends KeyMetadata> extends Provider {
+public interface KeyProvider extends Provider {
/**
- * Returns the algorithm type the keys can be used for
- *
+ * Returns the key
* @return
*/
- AlgorithmType getType();
+ List<KeyWrapper> getKeys();
- /**
- * Return the KID for the active keypair, or <code>null</code> if no active key is available.
- *
- * @return
- */
- String getKid();
-
- /**
- * Return metadata about all keypairs held by the provider
- * @return
- */
- List<T> getKeyMetadata();
+ default void close() {
+ }
}
diff --git a/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java b/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java
index be005b8..3c8766c 100644
--- a/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java
+++ b/server-spi-private/src/main/java/org/keycloak/keys/KeyProviderFactory.java
@@ -17,9 +17,11 @@
package org.keycloak.keys;
+import org.keycloak.Config;
import org.keycloak.component.ComponentFactory;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -28,4 +30,16 @@ public interface KeyProviderFactory<T extends KeyProvider> extends ComponentFact
T create(KeycloakSession session, ComponentModel model);
+ @Override
+ default void init(Config.Scope config) {
+ }
+
+ @Override
+ default void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ default void close() {
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 83a3756..5a9a4c7 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -17,33 +17,25 @@
package org.keycloak.broker.saml;
import org.jboss.logging.Logger;
-import org.keycloak.broker.provider.AbstractIdentityProvider;
-import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.BrokeredIdentityContext;
-import org.keycloak.broker.provider.IdentityBrokerException;
-import org.keycloak.broker.provider.IdentityProviderDataMarshaller;
+import org.keycloak.broker.provider.*;
import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.KeyStatus;
import org.keycloak.dom.saml.v2.assertion.AssertionType;
import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
import org.keycloak.dom.saml.v2.assertion.SubjectType;
+import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
import org.keycloak.events.EventBuilder;
import org.keycloak.keys.RsaKeyMetadata;
-import org.keycloak.models.FederatedIdentityModel;
-import org.keycloak.models.KeyManager;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.*;
import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
-import org.keycloak.saml.SAML2AuthnRequestBuilder;
-import org.keycloak.saml.SAML2LogoutRequestBuilder;
-import org.keycloak.saml.SAML2NameIDPolicyBuilder;
-import org.keycloak.saml.SPMetadataDescriptor;
-import org.keycloak.saml.SignatureAlgorithm;
+import org.keycloak.saml.*;
import org.keycloak.saml.common.constants.GeneralConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
+import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@@ -52,11 +44,6 @@ import javax.ws.rs.core.UriInfo;
import java.security.KeyPair;
import java.util.Set;
import java.util.TreeSet;
-import org.keycloak.dom.saml.v2.metadata.KeyTypes;
-import org.keycloak.keys.KeyMetadata;
-import org.keycloak.keys.KeyMetadata.Status;
-import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
-import org.keycloak.sessions.AuthenticationSessionModel;
/**
* @author Pedro Igor
@@ -246,12 +233,12 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
StringBuilder encryptionKeysString = new StringBuilder();
Set<RsaKeyMetadata> keys = new TreeSet<>((o1, o2) -> o1.getStatus() == o2.getStatus() // Status can be only PASSIVE OR ACTIVE, push PASSIVE to end of list
? (int) (o2.getProviderPriority() - o1.getProviderPriority())
- : (o1.getStatus() == KeyMetadata.Status.PASSIVE ? 1 : -1));
- keys.addAll(session.keys().getRsaKeys(realm, false));
+ : (o1.getStatus() == KeyStatus.PASSIVE ? 1 : -1));
+ keys.addAll(session.keys().getRsaKeys(realm));
for (RsaKeyMetadata key : keys) {
addKeyInfo(signingKeysString, key, KeyTypes.SIGNING.value());
- if (key.getStatus() == Status.ACTIVE) {
+ if (key.getStatus() == KeyStatus.ACTIVE) {
addKeyInfo(encryptionKeysString, key, KeyTypes.ENCRYPTION.value());
}
}
diff --git a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
index 0584a75..8a715b8 100644
--- a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProvider.java
@@ -17,13 +17,12 @@
package org.keycloak.keys;
+import org.keycloak.common.util.KeyUtils;
import org.keycloak.component.ComponentModel;
-import org.keycloak.jose.jws.AlgorithmType;
+import org.keycloak.crypto.*;
import org.keycloak.models.RealmModel;
import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
@@ -31,110 +30,49 @@ import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public abstract class AbstractRsaKeyProvider implements RsaKeyProvider {
+public abstract class AbstractRsaKeyProvider implements KeyProvider {
- private final boolean enabled;
-
- private final boolean active;
+ private final KeyStatus status;
private final ComponentModel model;
- private final Keys keys;
+ private final KeyWrapper key;
public AbstractRsaKeyProvider(RealmModel realm, ComponentModel model) {
this.model = model;
+ this.status = KeyStatus.from(model.get(Attributes.ACTIVE_KEY, true), model.get(Attributes.ENABLED_KEY, true));
- this.enabled = model.get(Attributes.ENABLED_KEY, true);
- this.active = model.get(Attributes.ACTIVE_KEY, true);
-
- if (model.hasNote(Keys.class.getName())) {
- keys = model.getNote(Keys.class.getName());
+ if (model.hasNote(KeyWrapper.class.getName())) {
+ key = model.getNote(KeyWrapper.class.getName());
} else {
- keys = loadKeys(realm, model);
- model.setNote(Keys.class.getName(), keys);
+ key = loadKey(realm, model);
+ model.setNote(KeyWrapper.class.getName(), key);
}
}
- protected abstract Keys loadKeys(RealmModel realm, ComponentModel model);
-
- @Override
- public final String getKid() {
- return isActive() ? keys.getKid() : null;
- }
-
- @Override
- public final PrivateKey getPrivateKey() {
- return isActive() ? keys.getKeyPair().getPrivate() : null;
- }
-
- @Override
- public final PublicKey getPublicKey(String kid) {
- return isEnabled() && kid.equals(keys.getKid()) ? keys.getKeyPair().getPublic() : null;
- }
-
- @Override
- public X509Certificate getCertificate(String kid) {
- return isEnabled() && kid.equals(keys.getKid()) ? keys.getCertificate() : null;
- }
-
- @Override
- public final List<RsaKeyMetadata> getKeyMetadata() {
- String kid = keys.getKid();
- PublicKey publicKey = keys.getKeyPair().getPublic();
- if (kid != null && publicKey != null) {
- RsaKeyMetadata k = new RsaKeyMetadata();
- k.setProviderId(model.getId());
- k.setProviderPriority(model.get(Attributes.PRIORITY_KEY, 0l));
- k.setKid(kid);
- if (isActive()) {
- k.setStatus(KeyMetadata.Status.ACTIVE);
- } else if (isEnabled()) {
- k.setStatus(KeyMetadata.Status.PASSIVE);
- } else {
- k.setStatus(KeyMetadata.Status.DISABLED);
- }
- k.setPublicKey(publicKey);
- k.setCertificate(keys.getCertificate());
- return Collections.singletonList(k);
- } else {
- return Collections.emptyList();
- }
- }
+ protected abstract KeyWrapper loadKey(RealmModel realm, ComponentModel model);
@Override
- public void close() {
- }
-
- private boolean isEnabled() {
- return keys != null && enabled;
+ public List<KeyWrapper> getKeys() {
+ return Collections.singletonList(key);
}
- private boolean isActive() {
- return isEnabled() && active;
- }
-
- public static class Keys {
- private String kid;
- private KeyPair keyPair;
- private X509Certificate certificate;
+ protected KeyWrapper createKeyWrapper(KeyPair keyPair, X509Certificate certificate) {
+ KeyWrapper key = new KeyWrapper();
- public Keys(String kid, KeyPair keyPair, X509Certificate certificate) {
- this.kid = kid;
- this.keyPair = keyPair;
- this.certificate = certificate;
- }
+ key.setProviderId(model.getId());
+ key.setProviderPriority(model.get("priority", 0l));
- public String getKid() {
- return kid;
- }
+ key.setKid(KeyUtils.createKeyId(keyPair.getPublic()));
+ key.setUse(KeyUse.SIG);
+ key.setType(KeyType.RSA);
+ key.setAlgorithms(Algorithm.RS256, Algorithm.RS384, Algorithm.RS512);
+ key.setStatus(status);
+ key.setSignKey(keyPair.getPrivate());
+ key.setVerifyKey(keyPair.getPublic());
+ key.setCertificate(certificate);
- public KeyPair getKeyPair() {
- return keyPair;
- }
-
- public X509Certificate getCertificate() {
- return certificate;
- }
+ return key;
}
}
diff --git a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java
index f20dc20..1c2af4f 100644
--- a/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/AbstractRsaKeyProviderFactory.java
@@ -27,7 +27,7 @@ import org.keycloak.provider.ProviderConfigurationBuilder;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public abstract class AbstractRsaKeyProviderFactory implements RsaKeyProviderFactory {
+public abstract class AbstractRsaKeyProviderFactory implements KeyProviderFactory {
public final static ProviderConfigurationBuilder configurationBuilder() {
return ProviderConfigurationBuilder.create()
diff --git a/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java b/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java
index 6a33293..7ebb1a4 100644
--- a/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java
+++ b/services/src/main/java/org/keycloak/keys/DefaultKeyManager.java
@@ -19,20 +19,19 @@ package org.keycloak.keys;
import org.jboss.logging.Logger;
import org.keycloak.component.ComponentModel;
-import org.keycloak.jose.jws.AlgorithmType;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.models.KeyManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.ProviderFactory;
import javax.crypto.SecretKey;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -49,204 +48,172 @@ public class DefaultKeyManager implements KeyManager {
}
@Override
- public ActiveRsaKey getActiveRsaKey(RealmModel realm) {
+ public KeyWrapper getActiveKey(RealmModel realm, KeyUse use, String algorithm) {
for (KeyProvider p : getProviders(realm)) {
- if (p.getType().equals(AlgorithmType.RSA)) {
- RsaKeyProvider r = (RsaKeyProvider) p;
- if (r.getKid() != null && r.getPrivateKey() != null) {
+ for (KeyWrapper key : p .getKeys()) {
+ if (key.getStatus().isActive() && matches(key, use, algorithm)) {
if (logger.isTraceEnabled()) {
- logger.tracev("Active key realm={0} kid={1}", realm.getName(), p.getKid());
+ logger.tracev("Active key found: realm={0} kid={1} algorithm={2}", realm.getName(), key.getKid(), algorithm);
}
- String kid = p.getKid();
- return new ActiveRsaKey(kid, r.getPrivateKey(), r.getPublicKey(kid), r.getCertificate(kid));
- }
- }
- }
- throw new RuntimeException("Failed to get RSA keys");
- }
-
- @Override
- public ActiveHmacKey getActiveHmacKey(RealmModel realm) {
- for (KeyProvider p : getProviders(realm)) {
- if (p.getType().equals(AlgorithmType.HMAC)) {
- HmacKeyProvider h = (HmacKeyProvider) p;
- if (h.getKid() != null && h.getSecretKey() != null) {
- if (logger.isTraceEnabled()) {
- logger.tracev("Active secret realm={0} kid={1}", realm.getName(), p.getKid());
- }
- String kid = p.getKid();
- return new ActiveHmacKey(kid, h.getSecretKey());
- }
- }
- }
- throw new RuntimeException("Failed to get keys");
- }
- @Override
- public ActiveAesKey getActiveAesKey(RealmModel realm) {
- for (KeyProvider p : getProviders(realm)) {
- if (p.getType().equals(AlgorithmType.AES)) {
- AesKeyProvider h = (AesKeyProvider) p;
- if (h.getKid() != null && h.getSecretKey() != null) {
- if (logger.isTraceEnabled()) {
- logger.tracev("Active AES Key realm={0} kid={1}", realm.getName(), p.getKid());
- }
- String kid = p.getKid();
- return new ActiveAesKey(kid, h.getSecretKey());
+ return key;
}
}
}
- throw new RuntimeException("Failed to get keys");
+ throw new RuntimeException("Failed to find key: realm=" + realm.getName() + " algorithm=" + algorithm);
}
@Override
- public PublicKey getRsaPublicKey(RealmModel realm, String kid) {
+ public KeyWrapper getKey(RealmModel realm, String kid, KeyUse use, String algorithm) {
if (kid == null) {
- logger.warnv("KID is null, can't find public key", realm.getName(), kid);
+ logger.warnv("kid is null, can't find public key", realm.getName(), kid);
return null;
}
for (KeyProvider p : getProviders(realm)) {
- if (p.getType().equals(AlgorithmType.RSA)) {
- RsaKeyProvider r = (RsaKeyProvider) p;
- PublicKey publicKey = r.getPublicKey(kid);
- if (publicKey != null) {
+ for (KeyWrapper key : p.getKeys()) {
+ if (key.getKid().equals(kid) && key.getStatus().isEnabled() && matches(key, use, algorithm)) {
if (logger.isTraceEnabled()) {
- logger.tracev("Found public key realm={0} kid={1}", realm.getName(), kid);
+ logger.tracev("Active key realm={0} kid={1} algorithm={2}", realm.getName(), key.getKid(), algorithm);
}
- return publicKey;
+
+ return key;
}
}
}
+
if (logger.isTraceEnabled()) {
- logger.tracev("Failed to find public key realm={0} kid={1}", realm.getName(), kid);
+ logger.tracev("Failed to find public key realm={0} kid={1} algorithm={2}", realm.getName(), kid, algorithm);
}
+
return null;
}
@Override
- public Certificate getRsaCertificate(RealmModel realm, String kid) {
- if (kid == null) {
- logger.warnv("KID is null, can't find public key", realm.getName(), kid);
- return null;
- }
-
+ public List<KeyWrapper> getKeys(RealmModel realm, KeyUse use, String algorithm) {
+ List<KeyWrapper> keys = new LinkedList<>();
for (KeyProvider p : getProviders(realm)) {
- if (p.getType().equals(AlgorithmType.RSA)) {
- RsaKeyProvider r = (RsaKeyProvider) p;
- Certificate certificate = r.getCertificate(kid);
- if (certificate != null) {
- if (logger.isTraceEnabled()) {
- logger.tracev("Found certificate realm={0} kid={1}", realm.getName(), kid);
- }
- return certificate;
+ for (KeyWrapper key : p .getKeys()) {
+ if (key.getStatus().isEnabled() && matches(key, use, algorithm)) {
+ keys.add(key);
}
}
}
- if (logger.isTraceEnabled()) {
- logger.tracev("Failed to find certificate realm={0} kid={1}", realm.getName(), kid);
- }
- return null;
+ return keys;
}
@Override
- public SecretKey getHmacSecretKey(RealmModel realm, String kid) {
- if (kid == null) {
- logger.warnv("KID is null, can't find secret key", realm.getName(), kid);
- return null;
- }
-
+ public List<KeyWrapper> getKeys(RealmModel realm) {
+ List<KeyWrapper> keys = new LinkedList<>();
for (KeyProvider p : getProviders(realm)) {
- if (p.getType().equals(AlgorithmType.HMAC)) {
- HmacKeyProvider h = (HmacKeyProvider) p;
- SecretKey s = h.getSecretKey(kid);
- if (s != null) {
- if (logger.isTraceEnabled()) {
- logger.tracev("Found secret key realm={0} kid={1}", realm.getName(), kid);
- }
- return s;
- }
+ for (KeyWrapper key : p .getKeys()) {
+ keys.add(key);
}
}
- if (logger.isTraceEnabled()) {
- logger.tracev("Failed to find secret key realm={0} kid={1}", realm.getName(), kid);
- }
- return null;
+ return keys;
}
@Override
- public SecretKey getAesSecretKey(RealmModel realm, String kid) {
- if (kid == null) {
- logger.warnv("KID is null, can't find aes key", realm.getName(), kid);
- return null;
- }
+ @Deprecated
+ public ActiveRsaKey getActiveRsaKey(RealmModel realm) {
+ KeyWrapper key = getActiveKey(realm, KeyUse.SIG, Algorithm.RS256);
+ return new ActiveRsaKey(key.getKid(), (PrivateKey) key.getSignKey(), (PublicKey) key.getVerifyKey(), key.getCertificate());
+ }
- for (KeyProvider p : getProviders(realm)) {
- if (p.getType().equals(AlgorithmType.AES)) {
- AesKeyProvider h = (AesKeyProvider) p;
- SecretKey s = h.getSecretKey(kid);
- if (s != null) {
- if (logger.isTraceEnabled()) {
- logger.tracev("Found AES key realm={0} kid={1}", realm.getName(), kid);
- }
- return s;
- }
- }
- }
- if (logger.isTraceEnabled()) {
- logger.tracev("Failed to find AES key realm={0} kid={1}", realm.getName(), kid);
- }
- return null;
+ @Override
+ @Deprecated
+ public ActiveHmacKey getActiveHmacKey(RealmModel realm) {
+ KeyWrapper key = getActiveKey(realm, KeyUse.SIG, Algorithm.HS256);
+ return new ActiveHmacKey(key.getKid(), key.getSecretKey());
}
@Override
- public List<RsaKeyMetadata> getRsaKeys(RealmModel realm, boolean includeDisabled) {
+ @Deprecated
+ public ActiveAesKey getActiveAesKey(RealmModel realm) {
+ KeyWrapper key = getActiveKey(realm, KeyUse.ENC, Algorithm.AES);
+ return new ActiveAesKey(key.getKid(), key.getSecretKey());
+ }
+
+ @Override
+ @Deprecated
+ public PublicKey getRsaPublicKey(RealmModel realm, String kid) {
+ KeyWrapper key = getKey(realm, kid, KeyUse.SIG, Algorithm.RS256);
+ return key != null ? (PublicKey) key.getVerifyKey() : null;
+ }
+
+ @Override
+ @Deprecated
+ public Certificate getRsaCertificate(RealmModel realm, String kid) {
+ KeyWrapper key = getKey(realm, kid, KeyUse.SIG, Algorithm.RS256);
+ return key != null ? key.getCertificate() : null;
+ }
+
+ @Override
+ @Deprecated
+ public SecretKey getHmacSecretKey(RealmModel realm, String kid) {
+ KeyWrapper key = getKey(realm, kid, KeyUse.SIG, Algorithm.HS256);
+ return key != null ? key.getSecretKey() : null;
+ }
+
+ @Override
+ @Deprecated
+ public SecretKey getAesSecretKey(RealmModel realm, String kid) {
+ KeyWrapper key = getKey(realm, kid, KeyUse.ENC, Algorithm.AES);
+ return key.getSecretKey();
+ }
+
+ @Override
+ @Deprecated
+ public List<RsaKeyMetadata> getRsaKeys(RealmModel realm) {
List<RsaKeyMetadata> keys = new LinkedList<>();
- for (KeyProvider p : getProviders(realm)) {
- if (p instanceof RsaKeyProvider) {
- if (includeDisabled) {
- keys.addAll(p.getKeyMetadata());
- } else {
- List<RsaKeyMetadata> metadata = p.getKeyMetadata();
- metadata.stream().filter(k -> k.getStatus() != KeyMetadata.Status.DISABLED).forEach(k -> keys.add(k));
- }
- }
+ for (KeyWrapper key : getKeys(realm, KeyUse.SIG, Algorithm.RS256)) {
+ RsaKeyMetadata m = new RsaKeyMetadata();
+ m.setCertificate(key.getCertificate());
+ m.setPublicKey((PublicKey) key.getVerifyKey());
+ m.setKid(key.getKid());
+ m.setProviderId(key.getProviderId());
+ m.setProviderPriority(key.getProviderPriority());
+ m.setStatus(key.getStatus());
+
+ keys.add(m);
}
return keys;
}
@Override
- public List<SecretKeyMetadata> getHmacKeys(RealmModel realm, boolean includeDisabled) {
+ public List<SecretKeyMetadata> getHmacKeys(RealmModel realm) {
List<SecretKeyMetadata> keys = new LinkedList<>();
- for (KeyProvider p : getProviders(realm)) {
- if (p instanceof HmacKeyProvider) {
- if (includeDisabled) {
- keys.addAll(p.getKeyMetadata());
- } else {
- List<SecretKeyMetadata> metadata = p.getKeyMetadata();
- metadata.stream().filter(k -> k.getStatus() != KeyMetadata.Status.DISABLED).forEach(k -> keys.add(k));
- }
- }
+ for (KeyWrapper key : getKeys(realm, KeyUse.SIG, Algorithm.HS256)) {
+ SecretKeyMetadata m = new SecretKeyMetadata();
+ m.setKid(key.getKid());
+ m.setProviderId(key.getProviderId());
+ m.setProviderPriority(key.getProviderPriority());
+ m.setStatus(key.getStatus());
+
+ keys.add(m);
}
return keys;
}
@Override
- public List<SecretKeyMetadata> getAesKeys(RealmModel realm, boolean includeDisabled) {
+ public List<SecretKeyMetadata> getAesKeys(RealmModel realm) {
List<SecretKeyMetadata> keys = new LinkedList<>();
- for (KeyProvider p : getProviders(realm)) {
- if (p instanceof AesKeyProvider) {
- if (includeDisabled) {
- keys.addAll(p.getKeyMetadata());
- } else {
- List<SecretKeyMetadata> metadata = p.getKeyMetadata();
- metadata.stream().filter(k -> k.getStatus() != KeyMetadata.Status.DISABLED).forEach(k -> keys.add(k));
- }
- }
+ for (KeyWrapper key : getKeys(realm, KeyUse.ENC, Algorithm.AES)) {
+ SecretKeyMetadata m = new SecretKeyMetadata();
+ m.setKid(key.getKid());
+ m.setProviderId(key.getProviderId());
+ m.setProviderPriority(key.getProviderPriority());
+ m.setStatus(key.getStatus());
+
+ keys.add(m);
}
return keys;
}
+ private boolean matches(KeyWrapper key, KeyUse use, String algorithm) {
+ return use.equals(key.getUse()) && key.getAlgorithms().contains(algorithm);
+ }
+
private List<KeyProvider> getProviders(RealmModel realm) {
List<KeyProvider> providers = providersMap.get(realm.getId());
if (providers == null) {
@@ -255,10 +222,6 @@ public class DefaultKeyManager implements KeyManager {
List<ComponentModel> components = new LinkedList<>(realm.getComponents(realm.getId(), KeyProvider.class.getName()));
components.sort(new ProviderComparator());
- boolean activeRsa = false;
- boolean activeHmac = false;
- boolean activeAes = false;
-
for (ComponentModel c : components) {
try {
ProviderFactory<KeyProvider> f = session.getKeycloakSessionFactory().getProviderFactory(KeyProvider.class, c.getProviderId());
@@ -266,41 +229,30 @@ public class DefaultKeyManager implements KeyManager {
KeyProvider provider = factory.create(session, c);
session.enlistForClose(provider);
providers.add(provider);
- if (provider.getType().equals(AlgorithmType.RSA)) {
- RsaKeyProvider r = (RsaKeyProvider) provider;
- if (r.getKid() != null && r.getPrivateKey() != null) {
- activeRsa = true;
- }
- } else if (provider.getType().equals(AlgorithmType.HMAC)) {
- HmacKeyProvider r = (HmacKeyProvider) provider;
- if (r.getKid() != null && r.getSecretKey() != null) {
- activeHmac = true;
- }
- } else if (provider.getType().equals(AlgorithmType.AES)) {
- AesKeyProvider r = (AesKeyProvider) provider;
- if (r.getKid() != null && r.getSecretKey() != null) {
- activeAes = true;
- }
- }
-
} catch (Throwable t) {
logger.errorv(t, "Failed to load provider {0}", c.getId());
}
}
- if (!activeRsa) {
+ providersMap.put(realm.getId(), providers);
+
+ try {
+ getActiveKey(realm, KeyUse.SIG, Algorithm.RS256);
+ } catch (RuntimeException e) {
providers.add(new FailsafeRsaKeyProvider());
}
- if (!activeHmac) {
+ try {
+ getActiveKey(realm, KeyUse.SIG, Algorithm.HS256);
+ } catch (RuntimeException e) {
providers.add(new FailsafeHmacKeyProvider());
}
- if (!activeAes) {
+ try {
+ getActiveKey(realm, KeyUse.ENC, Algorithm.AES);
+ } catch (RuntimeException e) {
providers.add(new FailsafeAesKeyProvider());
}
-
- providersMap.put(realm.getId(), providers);
}
return providers;
}
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java
index d81a596..bac9f76 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeAesKeyProvider.java
@@ -18,15 +18,33 @@
package org.keycloak.keys;
import org.jboss.logging.Logger;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
-public class FailsafeAesKeyProvider extends FailsafeSecretKeyProvider implements AesKeyProvider {
+public class FailsafeAesKeyProvider extends FailsafeSecretKeyProvider {
private static final Logger logger = Logger.getLogger(FailsafeAesKeyProvider.class);
@Override
+ protected KeyUse getUse() {
+ return KeyUse.ENC;
+ }
+
+ @Override
+ protected String getType() {
+ return KeyType.OCT;
+ }
+
+ @Override
+ protected String getAlgorithm() {
+ return Algorithm.AES;
+ }
+
+ @Override
protected Logger logger() {
return logger;
}
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java
index 676e048..1114c24 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeHmacKeyProvider.java
@@ -20,6 +20,10 @@ package org.keycloak.keys;
import org.jboss.logging.Logger;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.Time;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.crypto.SecretKey;
@@ -29,12 +33,28 @@ import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public class FailsafeHmacKeyProvider extends FailsafeSecretKeyProvider implements HmacKeyProvider {
+public class FailsafeHmacKeyProvider extends FailsafeSecretKeyProvider {
private static final Logger logger = Logger.getLogger(FailsafeHmacKeyProvider.class);
@Override
+ protected KeyUse getUse() {
+ return KeyUse.SIG;
+ }
+
+ @Override
+ protected String getType() {
+ return KeyType.OCT;
+ }
+
+ @Override
+ protected String getAlgorithm() {
+ return Algorithm.HS256;
+ }
+
+ @Override
protected Logger logger() {
return logger;
}
+
}
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java
index 8515f29..9af84a5 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeRsaKeyProvider.java
@@ -20,77 +20,62 @@ package org.keycloak.keys;
import org.jboss.logging.Logger;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.Time;
+import org.keycloak.crypto.*;
import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public class FailsafeRsaKeyProvider implements RsaKeyProvider {
+public class FailsafeRsaKeyProvider implements KeyProvider {
private static final Logger logger = Logger.getLogger(FailsafeRsaKeyProvider.class);
- private static String KID;
-
- private static KeyPair KEY_PAIR;
+ private static KeyWrapper KEY;
private static long EXPIRES;
- private KeyPair keyPair;
-
- private String kid;
+ private KeyWrapper key;
public FailsafeRsaKeyProvider() {
logger.errorv("No active keys found, using failsafe provider, please login to admin console to add keys. Clustering is not supported.");
synchronized (FailsafeRsaKeyProvider.class) {
if (EXPIRES < Time.currentTime()) {
- KEY_PAIR = KeyUtils.generateRsaKeyPair(2048);
- KID = KeyUtils.createKeyId(KEY_PAIR.getPublic());
+ KEY = createKeyWrapper();
EXPIRES = Time.currentTime() + 60 * 10;
if (EXPIRES > 0) {
- logger.warnv("Keys expired, re-generated kid={0}", KID);
+ logger.warnv("Keys expired, re-generated kid={0}", KEY.getKid());
}
}
- kid = KID;
- keyPair = KEY_PAIR;
+ key = KEY;
}
}
@Override
- public String getKid() {
- return kid;
+ public List<KeyWrapper> getKeys() {
+ return Collections.singletonList(key);
}
- @Override
- public PrivateKey getPrivateKey() {
- return keyPair.getPrivate();
- }
+ private KeyWrapper createKeyWrapper() {
+ KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
- @Override
- public PublicKey getPublicKey(String kid) {
- return kid.equals(this.kid) ? keyPair.getPublic() : null;
- }
+ KeyWrapper key = new KeyWrapper();
- @Override
- public X509Certificate getCertificate(String kid) {
- return null;
- }
+ key.setKid(KeyUtils.createKeyId(keyPair.getPublic()));
+ key.setUse(KeyUse.SIG);
+ key.setType(KeyType.RSA);
+ key.setAlgorithms(Algorithm.RS256, Algorithm.RS384, Algorithm.RS512);
+ key.setStatus(KeyStatus.ACTIVE);
+ key.setSignKey(keyPair.getPrivate());
+ key.setVerifyKey(keyPair.getPublic());
- @Override
- public List<RsaKeyMetadata> getKeyMetadata() {
- return Collections.emptyList();
+ return key;
}
- @Override
- public void close() {
- }
}
diff --git a/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java b/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java
index 32be263..2cb565d 100644
--- a/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/FailsafeSecretKeyProvider.java
@@ -17,74 +17,72 @@
package org.keycloak.keys;
-import java.util.Collections;
-import java.util.List;
-
-import javax.crypto.SecretKey;
-
import org.jboss.logging.Logger;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.Time;
+import org.keycloak.crypto.JavaAlgorithm;
+import org.keycloak.crypto.KeyStatus;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.models.utils.KeycloakModelUtils;
+import javax.crypto.SecretKey;
+import java.util.Collections;
+import java.util.List;
+
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public abstract class FailsafeSecretKeyProvider implements SecretKeyProvider {
-
-
- private static String KID;
+public abstract class FailsafeSecretKeyProvider implements KeyProvider {
- private static SecretKey KEY;
+ private static KeyWrapper KEY;
private static long EXPIRES;
- private SecretKey key;
-
- private String kid;
+ private KeyWrapper key;
public FailsafeSecretKeyProvider() {
logger().errorv("No active keys found, using failsafe provider, please login to admin console to add keys. Clustering is not supported.");
synchronized (FailsafeHmacKeyProvider.class) {
if (EXPIRES < Time.currentTime()) {
- KEY = KeyUtils.loadSecretKey(KeycloakModelUtils.generateSecret(32), getJavaAlgorithmName());
- KID = KeycloakModelUtils.generateId();
+ KEY = createKeyWrapper();
EXPIRES = Time.currentTime() + 60 * 10;
if (EXPIRES > 0) {
- logger().warnv("Keys expired, re-generated kid={0}", KID);
+ logger().warnv("Keys expired, re-generated kid={0}", KEY.getKid());
}
}
- kid = KID;
key = KEY;
}
}
@Override
- public String getKid() {
- return kid;
+ public List<KeyWrapper> getKeys() {
+ return Collections.singletonList(key);
}
- @Override
- public SecretKey getSecretKey() {
+ private KeyWrapper createKeyWrapper() {
+ SecretKey secretKey = KeyUtils.loadSecretKey(KeycloakModelUtils.generateSecret(32), JavaAlgorithm.getJavaAlgorithm(getAlgorithm()));
+
+ KeyWrapper key = new KeyWrapper();
+
+ key.setKid(KeycloakModelUtils.generateId());
+ key.setUse(getUse());
+ key.setType(getType());
+ key.setAlgorithms(getAlgorithm());
+ key.setStatus(KeyStatus.ACTIVE);
+ key.setSecretKey(secretKey);
+
return key;
}
- @Override
- public SecretKey getSecretKey(String kid) {
- return kid.equals(this.kid) ? key : null;
- }
+ protected abstract KeyUse getUse();
- @Override
- public List<SecretKeyMetadata> getKeyMetadata() {
- return Collections.emptyList();
- }
+ protected abstract String getType();
- @Override
- public void close() {
- }
+ protected abstract String getAlgorithm();
protected abstract Logger logger();
}
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java
index cb07323..5a25f31 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProvider.java
@@ -18,14 +18,17 @@
package org.keycloak.keys;
import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
-public class GeneratedAesKeyProvider extends GeneratedSecretKeyProvider implements AesKeyProvider {
+public class GeneratedAesKeyProvider extends GeneratedSecretKeyProvider implements KeyProvider {
public GeneratedAesKeyProvider(ComponentModel model) {
- super(model);
+ super(model, KeyUse.ENC, KeyType.OCT, Algorithm.AES);
}
}
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java
index b9f5a06..e8974aa 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedAesKeyProviderFactory.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.jboss.logging.Logger;
import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.KeyUse;
import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.ProviderConfigProperty;
@@ -29,7 +30,7 @@ import static org.keycloak.provider.ProviderConfigProperty.LIST_TYPE;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
-public class GeneratedAesKeyProviderFactory extends GeneratedSecretKeyProviderFactory<AesKeyProvider> implements AesKeyProviderFactory {
+public class GeneratedAesKeyProviderFactory extends GeneratedSecretKeyProviderFactory<GeneratedSecretKeyProvider> {
private static final Logger logger = Logger.getLogger(GeneratedAesKeyProviderFactory.class);
@@ -52,7 +53,7 @@ public class GeneratedAesKeyProviderFactory extends GeneratedSecretKeyProviderFa
.build();
@Override
- public AesKeyProvider create(KeycloakSession session, ComponentModel model) {
+ public GeneratedAesKeyProvider create(KeycloakSession session, ComponentModel model) {
return new GeneratedAesKeyProvider(model);
}
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java
index dfc8fb2..2367a16 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProvider.java
@@ -18,15 +18,18 @@
package org.keycloak.keys;
import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyUse;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public class GeneratedHmacKeyProvider extends GeneratedSecretKeyProvider implements HmacKeyProvider {
+public class GeneratedHmacKeyProvider extends GeneratedSecretKeyProvider {
public GeneratedHmacKeyProvider(ComponentModel model) {
- super(model);
+ super(model, KeyUse.SIG, KeyType.OCT, Algorithm.HS256);
}
}
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java
index ab4902a..9f58876 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedHmacKeyProviderFactory.java
@@ -34,7 +34,7 @@ import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public class GeneratedHmacKeyProviderFactory extends GeneratedSecretKeyProviderFactory<HmacKeyProvider> implements HmacKeyProviderFactory {
+public class GeneratedHmacKeyProviderFactory extends GeneratedSecretKeyProviderFactory<GeneratedHmacKeyProvider> {
private static final Logger logger = Logger.getLogger(GeneratedHmacKeyProviderFactory.class);
@@ -49,7 +49,7 @@ public class GeneratedHmacKeyProviderFactory extends GeneratedSecretKeyProviderF
.build();
@Override
- public HmacKeyProvider create(KeycloakSession session, ComponentModel model) {
+ public GeneratedHmacKeyProvider create(KeycloakSession session, ComponentModel model) {
return new GeneratedHmacKeyProvider(model);
}
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java
index a0a5e87..4aa10da 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedRsaKeyProviderFactory.java
@@ -111,18 +111,6 @@ public class GeneratedRsaKeyProviderFactory extends AbstractRsaKeyProviderFactor
}
@Override
- public void init(Config.Scope config) {
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
- }
-
- @Override
- public void close() {
- }
-
- @Override
public String getId() {
return ID;
}
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java
index 76b7ea8..1d416d2 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProvider.java
@@ -17,86 +17,67 @@
package org.keycloak.keys;
-import java.util.Collections;
-import java.util.List;
-
-import javax.crypto.SecretKey;
-
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.JavaAlgorithm;
+import org.keycloak.crypto.KeyStatus;
+import org.keycloak.crypto.KeyUse;
+import org.keycloak.crypto.KeyWrapper;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import javax.crypto.SecretKey;
+import java.util.Collections;
+import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
-public abstract class GeneratedSecretKeyProvider implements SecretKeyProvider {
-
- private final boolean enabled;
-
- private final boolean active;
+public abstract class GeneratedSecretKeyProvider implements KeyProvider {
+ private final KeyStatus status;
private final ComponentModel model;
private final String kid;
private final SecretKey secretKey;
+ private final KeyUse use;
+ private String type;
+ private final String algorithm;
- public GeneratedSecretKeyProvider(ComponentModel model) {
- this.enabled = model.get(Attributes.ENABLED_KEY, true);
- this.active = model.get(Attributes.ACTIVE_KEY, true);
+ public GeneratedSecretKeyProvider(ComponentModel model, KeyUse use, String type, String algorithm) {
+ this.status = KeyStatus.from(model.get(Attributes.ACTIVE_KEY, true), model.get(Attributes.ENABLED_KEY, true));
this.kid = model.get(Attributes.KID_KEY);
this.model = model;
+ this.use = use;
+ this.type = type;
+ this.algorithm = algorithm;
if (model.hasNote(SecretKey.class.getName())) {
secretKey = model.getNote(SecretKey.class.getName());
} else {
- secretKey = KeyUtils.loadSecretKey(Base64Url.decode(model.get(Attributes.SECRET_KEY)), getJavaAlgorithmName());
+ secretKey = KeyUtils.loadSecretKey(Base64Url.decode(model.get(Attributes.SECRET_KEY)), JavaAlgorithm.getJavaAlgorithm(algorithm));
model.setNote(SecretKey.class.getName(), secretKey);
}
}
@Override
- public SecretKey getSecretKey() {
- return isActive() ? secretKey : null;
- }
+ public List<KeyWrapper> getKeys() {
+ KeyWrapper key = new KeyWrapper();
- @Override
- public SecretKey getSecretKey(String kid) {
- return isEnabled() && kid.equals(this.kid) ? secretKey : null;
- }
+ key.setProviderId(model.getId());
+ key.setProviderPriority(model.get("priority", 0l));
- @Override
- public String getKid() {
- return isActive() ? kid : null;
- }
+ key.setKid(kid);
+ key.setUse(use);
+ key.setType(type);
+ key.setAlgorithms(algorithm);
+ key.setStatus(status);
+ key.setSecretKey(secretKey);
- @Override
- public List<SecretKeyMetadata> getKeyMetadata() {
- if (kid != null && secretKey != null) {
- SecretKeyMetadata k = new SecretKeyMetadata();
- k.setProviderId(model.getId());
- k.setProviderPriority(model.get(Attributes.PRIORITY_KEY, 0l));
- k.setKid(kid);
- if (isActive()) {
- k.setStatus(KeyMetadata.Status.ACTIVE);
- } else if (isEnabled()) {
- k.setStatus(KeyMetadata.Status.PASSIVE);
- } else {
- k.setStatus(KeyMetadata.Status.DISABLED);
- }
- return Collections.singletonList(k);
- } else {
- return Collections.emptyList();
- }
+ return Collections.singletonList(key);
}
@Override
public void close() {
}
- private boolean isEnabled() {
- return secretKey != null && enabled;
- }
-
- private boolean isActive() {
- return isEnabled() && active;
- }
}
diff --git a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java
index 3211cfc..c6c5d41 100644
--- a/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/GeneratedSecretKeyProviderFactory.java
@@ -66,17 +66,5 @@ public abstract class GeneratedSecretKeyProviderFactory<T extends KeyProvider> i
protected abstract Logger logger();
- @Override
- public void init(Config.Scope config) {
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
- }
-
- @Override
- public void close() {
- }
-
protected abstract int getDefaultKeySize();
}
diff --git a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java
index 6fd7a92..67968a4 100644
--- a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProvider.java
@@ -20,6 +20,7 @@ package org.keycloak.keys;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.models.RealmModel;
import java.security.KeyPair;
@@ -38,7 +39,7 @@ public class ImportedRsaKeyProvider extends AbstractRsaKeyProvider {
}
@Override
- public Keys loadKeys(RealmModel realm, ComponentModel model) {
+ public KeyWrapper loadKey(RealmModel realm, ComponentModel model) {
String privateRsaKeyPem = model.getConfig().getFirst(Attributes.PRIVATE_KEY_KEY);
String certificatePem = model.getConfig().getFirst(Attributes.CERTIFICATE_KEY);
@@ -48,9 +49,7 @@ public class ImportedRsaKeyProvider extends AbstractRsaKeyProvider {
KeyPair keyPair = new KeyPair(publicKey, privateKey);
X509Certificate certificate = PemUtils.decodeCertificate(certificatePem);
- String kid = KeyUtils.createKeyId(keyPair.getPublic());
-
- return new Keys(kid, keyPair, certificate);
+ return createKeyWrapper(keyPair, certificate);
}
}
diff --git a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java
index 5dbe4bc..d46a77a 100644
--- a/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/ImportedRsaKeyProviderFactory.java
@@ -17,14 +17,12 @@
package org.keycloak.keys;
-import org.keycloak.Config;
import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.component.ComponentModel;
import org.keycloak.component.ComponentValidationException;
import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.ConfigurationValidationHelper;
import org.keycloak.provider.ProviderConfigProperty;
@@ -107,18 +105,6 @@ public class ImportedRsaKeyProviderFactory extends AbstractRsaKeyProviderFactory
}
@Override
- public void init(Config.Scope config) {
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
- }
-
- @Override
- public void close() {
- }
-
- @Override
public String getId() {
return ID;
}
diff --git a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
index 8c98bb4..ba5dfc6 100644
--- a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
+++ b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProvider.java
@@ -17,23 +17,16 @@
package org.keycloak.keys;
-import org.jboss.logging.Logger;
import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.component.ComponentModel;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.models.RealmModel;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.security.KeyPair;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
+import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@@ -42,14 +35,12 @@ import java.security.cert.X509Certificate;
*/
public class JavaKeystoreKeyProvider extends AbstractRsaKeyProvider {
- private static final Logger logger = Logger.getLogger(JavaKeystoreKeyProvider.class);
-
public JavaKeystoreKeyProvider(RealmModel realm, ComponentModel model) {
super(realm, model);
}
@Override
- protected Keys loadKeys(RealmModel realm, ComponentModel model) {
+ protected KeyWrapper loadKey(RealmModel realm, ComponentModel model) {
try {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(model.get(JavaKeystoreKeyProviderFactory.KEYSTORE_KEY)), model.get(JavaKeystoreKeyProviderFactory.KEYSTORE_PASSWORD_KEY).toCharArray());
@@ -64,9 +55,7 @@ public class JavaKeystoreKeyProvider extends AbstractRsaKeyProvider {
certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, realm.getName());
}
- String kid = KeyUtils.createKeyId(keyPair.getPublic());
-
- return new Keys(kid, keyPair, certificate);
+ return createKeyWrapper(keyPair, certificate);
} catch (KeyStoreException kse) {
throw new RuntimeException("KeyStore error on server. " + kse.getMessage(), kse);
} catch (FileNotFoundException fnfe) {
diff --git a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
index 51b726a..325be9e 100644
--- a/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
+++ b/services/src/main/java/org/keycloak/keys/JavaKeystoreKeyProviderFactory.java
@@ -77,7 +77,7 @@ public class JavaKeystoreKeyProviderFactory extends AbstractRsaKeyProviderFactor
try {
new JavaKeystoreKeyProvider(session.getContext().getRealm(), model)
- .loadKeys(session.getContext().getRealm(), model);
+ .loadKey(session.getContext().getRealm(), model);
} catch (Throwable t) {
logger.error("Failed to load keys.", t);
throw new ComponentValidationException("Failed to load keys. " + t.getMessage(), t);
@@ -95,18 +95,6 @@ public class JavaKeystoreKeyProviderFactory extends AbstractRsaKeyProviderFactor
}
@Override
- public void init(Config.Scope config) {
- }
-
- @Override
- public void postInit(KeycloakSessionFactory factory) {
- }
-
- @Override
- public void close() {
- }
-
- @Override
public String getId() {
return ID;
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
index 6fa6705..c1952a5 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
@@ -26,7 +26,6 @@ import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.jose.jwk.JWK;
import org.keycloak.jose.jwk.JWKBuilder;
-import org.keycloak.keys.KeyMetadata;
import org.keycloak.keys.RsaKeyMetadata;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
@@ -195,7 +194,7 @@ public class OIDCLoginProtocolService {
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public Response certs() {
- List<RsaKeyMetadata> publicKeys = session.keys().getRsaKeys(realm, false);
+ List<RsaKeyMetadata> publicKeys = session.keys().getRsaKeys(realm);
JWK[] keys = new JWK[publicKeys.size()];
int i = 0;
diff --git a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
index 2261d52..b3b6d6a 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlIDPDescriptorClientInstallation.java
@@ -19,6 +19,8 @@ package org.keycloak.protocol.saml.installation;
import org.keycloak.Config;
import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.KeyStatus;
+import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.keys.RsaKeyMetadata;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
@@ -27,6 +29,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.protocol.ClientInstallationProvider;
import org.keycloak.protocol.saml.SamlClient;
import org.keycloak.protocol.saml.SamlProtocol;
+import org.keycloak.saml.SPMetadataDescriptor;
import org.keycloak.services.resources.RealmsResource;
import javax.ws.rs.core.MediaType;
@@ -35,9 +38,6 @@ import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.Set;
import java.util.TreeSet;
-import org.keycloak.dom.saml.v2.metadata.KeyTypes;
-import org.keycloak.keys.KeyMetadata;
-import org.keycloak.saml.SPMetadataDescriptor;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -90,8 +90,8 @@ public class SamlIDPDescriptorClientInstallation implements ClientInstallationPr
// keys
Set<RsaKeyMetadata> keys = new TreeSet<>((o1, o2) -> o1.getStatus() == o2.getStatus() // Status can be only PASSIVE OR ACTIVE, push PASSIVE to end of list
? (int) (o2.getProviderPriority() - o1.getProviderPriority())
- : (o1.getStatus() == KeyMetadata.Status.PASSIVE ? 1 : -1));
- keys.addAll(session.keys().getRsaKeys(realm, false));
+ : (o1.getStatus() == KeyStatus.PASSIVE ? 1 : -1));
+ keys.addAll(session.keys().getRsaKeys(realm));
for (RsaKeyMetadata key : keys) {
addKeyInfo(sb, key, KeyTypes.SIGNING.value());
}
diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
index e6f1833..b98727c 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -23,6 +23,7 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.common.VerificationException;
import org.keycloak.common.util.PemUtils;
import org.keycloak.common.util.StreamUtil;
+import org.keycloak.crypto.KeyStatus;
import org.keycloak.dom.saml.v2.SAML2Object;
import org.keycloak.dom.saml.v2.assertion.BaseIDAbstractType;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
@@ -80,7 +81,6 @@ import java.util.Set;
import java.util.TreeSet;
import org.keycloak.common.util.StringPropertyReplacer;
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
-import org.keycloak.keys.KeyMetadata;
import org.keycloak.rotation.HardcodedKeyLocator;
import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.SPMetadataDescriptor;
@@ -591,8 +591,8 @@ public class SamlService extends AuthorizationEndpointBase {
StringBuilder keysString = new StringBuilder();
Set<RsaKeyMetadata> keys = new TreeSet<>((o1, o2) -> o1.getStatus() == o2.getStatus() // Status can be only PASSIVE OR ACTIVE, push PASSIVE to end of list
? (int) (o2.getProviderPriority() - o1.getProviderPriority())
- : (o1.getStatus() == KeyMetadata.Status.PASSIVE ? 1 : -1));
- keys.addAll(session.keys().getRsaKeys(realm, false));
+ : (o1.getStatus() == KeyStatus.PASSIVE ? 1 : -1));
+ keys.addAll(session.keys().getRsaKeys(realm));
for (RsaKeyMetadata key : keys) {
addKeyInfo(keysString, key, KeyTypes.SIGNING.value());
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java b/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
index 87bb486..da0f3cb 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/KeyResource.java
@@ -19,9 +19,9 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.KeyWrapper;
import org.keycloak.jose.jws.AlgorithmType;
import org.keycloak.keys.SecretKeyMetadata;
-import org.keycloak.keys.RsaKeyMetadata;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeyManager;
import org.keycloak.models.RealmModel;
@@ -58,48 +58,30 @@ public class KeyResource {
public KeysMetadataRepresentation getKeyMetadata() {
auth.realm().requireViewRealm();
- KeyManager keystore = session.keys();
-
KeysMetadataRepresentation keys = new KeysMetadataRepresentation();
+ keys.setKeys(new LinkedList<>());
+ keys.setActive(new HashMap<>());
- Map<String, String> active = new HashMap<>();
- active.put(AlgorithmType.RSA.name(), keystore.getActiveRsaKey(realm).getKid());
- active.put(AlgorithmType.HMAC.name(), keystore.getActiveHmacKey(realm).getKid());
- active.put(AlgorithmType.AES.name(), keystore.getActiveAesKey(realm).getKid());
- keys.setActive(active);
-
- List<KeysMetadataRepresentation.KeyMetadataRepresentation> l = new LinkedList<>();
- for (RsaKeyMetadata m : session.keys().getRsaKeys(realm, true)) {
- KeysMetadataRepresentation.KeyMetadataRepresentation r = new KeysMetadataRepresentation.KeyMetadataRepresentation();
- r.setProviderId(m.getProviderId());
- r.setProviderPriority(m.getProviderPriority());
- r.setKid(m.getKid());
- r.setStatus(m.getStatus() != null ? m.getStatus().name() : null);
- r.setType(AlgorithmType.RSA.name());
- r.setPublicKey(PemUtils.encodeKey(m.getPublicKey()));
- r.setCertificate(PemUtils.encodeCertificate(m.getCertificate()));
- l.add(r);
- }
- for (SecretKeyMetadata m : session.keys().getHmacKeys(realm, true)) {
+ for (KeyWrapper key : session.keys().getKeys(realm)) {
KeysMetadataRepresentation.KeyMetadataRepresentation r = new KeysMetadataRepresentation.KeyMetadataRepresentation();
- r.setProviderId(m.getProviderId());
- r.setProviderPriority(m.getProviderPriority());
- r.setKid(m.getKid());
- r.setStatus(m.getStatus() != null ? m.getStatus().name() : null);
- r.setType(AlgorithmType.HMAC.name());
- l.add(r);
- }
- for (SecretKeyMetadata m : session.keys().getAesKeys(realm, true)) {
- KeysMetadataRepresentation.KeyMetadataRepresentation r = new KeysMetadataRepresentation.KeyMetadataRepresentation();
- r.setProviderId(m.getProviderId());
- r.setProviderPriority(m.getProviderPriority());
- r.setKid(m.getKid());
- r.setStatus(m.getStatus() != null ? m.getStatus().name() : null);
- r.setType(AlgorithmType.AES.name());
- l.add(r);
- }
+ r.setProviderId(key.getProviderId());
+ r.setProviderPriority(key.getProviderPriority());
+ r.setKid(key.getKid());
+ r.setStatus(key.getStatus() != null ? key.getStatus().name() : null);
+ r.setType(key.getType());
+ r.setAlgorithms(key.getAlgorithms());
+ r.setPublicKey(key.getVerifyKey() != null ? PemUtils.encodeKey(key.getVerifyKey()) : null);
+ r.setCertificate(key.getCertificate() != null ? PemUtils.encodeCertificate(key.getCertificate()) : null);
+ keys.getKeys().add(r);
- keys.setKeys(l);
+ if (key.getStatus().isActive()) {
+ for (String a : key.getAlgorithms()) {
+ if (!keys.getActive().containsKey(a)) {
+ keys.getActive().put(a, key.getKid());
+ }
+ }
+ }
+ }
return keys;
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
index 208ae91..7bff5ac 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/admin/ApiUtil.java
@@ -23,6 +23,7 @@ import org.keycloak.admin.client.resource.ClientScopeResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.crypto.Algorithm;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ClientScopeRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
@@ -255,7 +256,7 @@ public class ApiUtil {
public static KeysMetadataRepresentation.KeyMetadataRepresentation findActiveKey(RealmResource realm) {
KeysMetadataRepresentation keyMetadata = realm.keys().getKeyMetadata();
- String activeKid = keyMetadata.getActive().get("RSA");
+ String activeKid = keyMetadata.getActive().get(Algorithm.RS256);
for (KeysMetadataRepresentation.KeyMetadataRepresentation rep : keyMetadata.getKeys()) {
if (rep.getKid().equals(activeKid)) {
return rep;
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
index afe2f51..2862755 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
@@ -1,6 +1,7 @@
package org.keycloak.testsuite.util;
import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.representations.idm.KeysMetadataRepresentation;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
@@ -39,4 +40,15 @@ public class KeyUtils {
throw new RuntimeException(e);
}
}
+
+ public static KeysMetadataRepresentation.KeyMetadataRepresentation getActiveKey(KeysMetadataRepresentation keys, String algorithm) {
+ String kid = keys.getActive().get(algorithm);
+ for (KeysMetadataRepresentation.KeyMetadataRepresentation k : keys.getKeys()) {
+ if (k.getKid().equals(kid)) {
+ return k;
+ }
+ }
+ throw new RuntimeException("Active key not found");
+ }
+
}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
index 9e0f12d..21186bd 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
@@ -38,6 +38,7 @@ import org.keycloak.common.VerificationException;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.common.util.PemUtils;
import org.keycloak.constants.AdapterConstants;
+import org.keycloak.crypto.Algorithm;
import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
@@ -1099,7 +1100,7 @@ public class OAuthClient {
public PublicKey getRealmPublicKey(String realm) {
if (!publicKeys.containsKey(realm)) {
KeysMetadataRepresentation keyMetadata = adminClient.realms().realm(realm).keys().getKeyMetadata();
- String activeKid = keyMetadata.getActive().get("RSA");
+ String activeKid = keyMetadata.getActive().get(Algorithm.RS256);
PublicKey publicKey = null;
for (KeysMetadataRepresentation.KeyMetadataRepresentation rep : keyMetadata.getKeys()) {
if (rep.getKid().equals(activeKid)) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java
index a1cb309..bd10c3a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/OIDCPublicKeyRotationAdapterTest.java
@@ -42,7 +42,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.StreamUtil;
import org.keycloak.common.util.Time;
import org.keycloak.constants.AdapterConstants;
-import org.keycloak.jose.jws.AlgorithmType;
+import org.keycloak.crypto.Algorithm;
import org.keycloak.keys.KeyProvider;
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
@@ -308,7 +308,7 @@ public class OIDCPublicKeyRotationAdapterTest extends AbstractServletsAdapterTes
private String getActiveKeyProvider() {
KeysMetadataRepresentation keyMetadata = adminClient.realm(DEMO).keys().getKeyMetadata();
- String activeKid = keyMetadata.getActive().get(AlgorithmType.RSA.name());
+ String activeKid = keyMetadata.getActive().get(Algorithm.RS256);
for (KeysMetadataRepresentation.KeyMetadataRepresentation rep : keyMetadata.getKeys()) {
if (rep.getKid().equals(activeKid)) {
return rep.getProviderId();
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 83496a3..f98a5fc 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
@@ -28,6 +28,7 @@ import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.common.util.*;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.crypto.Algorithm;
import org.keycloak.keys.KeyProvider;
import org.keycloak.keys.PublicKeyStorageUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
@@ -293,7 +294,7 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest {
private void rotateKeys() {
- String activeKid = providerRealm().keys().getKeyMetadata().getActive().get("RSA");
+ String activeKid = providerRealm().keys().getKeyMetadata().getActive().get(Algorithm.RS256);
// Rotate public keys on the parent broker
String realmId = providerRealm().toRepresentation().getId();
@@ -308,7 +309,7 @@ public class KcOIDCBrokerWithSignatureTest extends AbstractBaseBrokerTest {
assertEquals(201, response.getStatus());
response.close();
- String updatedActiveKid = providerRealm().keys().getKeyMetadata().getActive().get("RSA");
+ String updatedActiveKid = providerRealm().keys().getKeyMetadata().getActive().get(Algorithm.RS256);
assertNotEquals(activeKid, updatedActiveKid);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
index e447998..6887f74 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
@@ -2,10 +2,12 @@ package org.keycloak.testsuite.broker;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
+import org.keycloak.crypto.Algorithm;
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
import org.keycloak.protocol.saml.SamlConfigAttributes;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.util.DocumentUtil;
@@ -16,6 +18,7 @@ import org.keycloak.testsuite.arquillian.SuiteContext;
import org.keycloak.testsuite.saml.AbstractSamlTest;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.updaters.IdentityProviderAttributeUpdater;
+import org.keycloak.testsuite.util.KeyUtils;
import org.keycloak.testsuite.util.SamlClient;
import org.keycloak.testsuite.util.SamlClient.Binding;
import org.keycloak.testsuite.util.SamlClientBuilder;
@@ -66,7 +69,7 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
public List<ClientRepresentation> createProviderClients(SuiteContext suiteContext) {
List<ClientRepresentation> clientRepresentationList = super.createProviderClients(suiteContext);
- String consumerCert = adminClient.realm(consumerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+ String consumerCert = KeyUtils.getActiveKey(adminClient.realm(consumerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
Assert.assertThat(consumerCert, Matchers.notNullValue());
for (ClientRepresentation client : clientRepresentationList) {
@@ -93,7 +96,7 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
public IdentityProviderRepresentation setUpIdentityProvider(SuiteContext suiteContext) {
IdentityProviderRepresentation result = super.setUpIdentityProvider(suiteContext);
- String providerCert = adminClient.realm(providerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+ String providerCert = KeyUtils.getActiveKey(adminClient.realm(providerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
Assert.assertThat(providerCert, Matchers.notNullValue());
Map<String, String> config = result.getConfig();
@@ -121,10 +124,10 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
final ClientResource clientResource = realmsResouce().realm(bc.providerRealmName()).clients().get(client.getId());
Assert.assertThat(clientResource, Matchers.notNullValue());
- String providerCert = adminClient.realm(bc.providerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+ String providerCert = KeyUtils.getActiveKey(adminClient.realm(bc.providerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
Assert.assertThat(providerCert, Matchers.notNullValue());
- String consumerCert = adminClient.realm(bc.consumerRealmName()).keys().getKeyMetadata().getKeys().get(0).getCertificate();
+ String consumerCert = KeyUtils.getActiveKey(adminClient.realm(bc.consumerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
Assert.assertThat(consumerCert, Matchers.notNullValue());
try (Closeable idpUpdater = new IdentityProviderAttributeUpdater(identityProviderResource)
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java
index efddeea..4734ffd 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/GeneratedHmacKeyProviderTest.java
@@ -24,6 +24,8 @@ import org.junit.Rule;
import org.junit.Test;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyType;
import org.keycloak.jose.jws.AlgorithmType;
import org.keycloak.keys.GeneratedHmacKeyProviderFactory;
import org.keycloak.keys.KeyProvider;
@@ -90,14 +92,14 @@ public class GeneratedHmacKeyProviderTest extends AbstractKeycloakTest {
KeysMetadataRepresentation.KeyMetadataRepresentation key = null;
for (KeysMetadataRepresentation.KeyMetadataRepresentation k : keys.getKeys()) {
- if (k.getType().equals(AlgorithmType.HMAC.name())) {
+ if (k.getAlgorithms().contains(Algorithm.HS256)) {
key = k;
break;
}
}
assertEquals(id, key.getProviderId());
- assertEquals(AlgorithmType.HMAC.name(), key.getType());
+ assertEquals(KeyType.OCT, key.getType());
assertEquals(priority, key.getProviderPriority());
ComponentRepresentation component = testingClient.server("test").fetch(RunHelpers.internalComponent(id));
@@ -125,14 +127,14 @@ public class GeneratedHmacKeyProviderTest extends AbstractKeycloakTest {
KeysMetadataRepresentation.KeyMetadataRepresentation key = null;
for (KeysMetadataRepresentation.KeyMetadataRepresentation k : keys.getKeys()) {
- if (k.getType().equals(AlgorithmType.HMAC.name())) {
+ if (k.getAlgorithms().contains(Algorithm.HS256)) {
key = k;
break;
}
}
assertEquals(id, key.getProviderId());
- assertEquals(AlgorithmType.HMAC.name(), key.getType());
+ assertEquals(KeyType.OCT, key.getType());
assertEquals(priority, key.getProviderPriority());
ComponentRepresentation component = testingClient.server("test").fetch(RunHelpers.internalComponent(id));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java
index e8d11ec..47e850e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/keys/ImportedRsaKeyProviderTest.java
@@ -24,6 +24,7 @@ import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.Algorithm;
import org.keycloak.jose.jws.AlgorithmType;
import org.keycloak.keys.Attributes;
import org.keycloak.keys.ImportedRsaKeyProviderFactory;
@@ -90,7 +91,7 @@ public class ImportedRsaKeyProviderTest extends AbstractKeycloakTest {
KeysMetadataRepresentation keys = adminClient.realm("test").keys().getKeyMetadata();
- assertEquals(kid, keys.getActive().get(AlgorithmType.RSA.name()));
+ assertEquals(kid, keys.getActive().get(Algorithm.RS256));
KeysMetadataRepresentation.KeyMetadataRepresentation key = keys.getKeys().get(0);
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 9700a29..cbc8db5 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
@@ -30,6 +30,7 @@ import org.keycloak.common.VerificationException;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.Algorithm;
import org.keycloak.keys.Attributes;
import org.keycloak.keys.GeneratedHmacKeyProviderFactory;
import org.keycloak.keys.KeyProvider;
@@ -218,7 +219,7 @@ public class KeyRotationTest extends AbstractKeycloakTest {
PublicKey keys2 = createKeys2();
KeysMetadataRepresentation keyMetadata = adminClient.realm("test").keys().getKeyMetadata();
- assertEquals(PemUtils.encodeKey(keys2), keyMetadata.getKeys().get(0).getPublicKey());
+ assertEquals(PemUtils.encodeKey(keys2), org.keycloak.testsuite.util.KeyUtils.getActiveKey(keyMetadata, Algorithm.RS256).getPublicKey());
dropKeys1();
dropKeys2();
@@ -227,7 +228,7 @@ public class KeyRotationTest extends AbstractKeycloakTest {
@Test
public void rotateKeys() throws InterruptedException {
for (int i = 0; i < 10; i++) {
- String activeKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get("RSA");
+ String activeKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get(Algorithm.RS256);
// Rotate public keys on the parent broker
String realmId = adminClient.realm("test").toRepresentation().getId();
@@ -244,7 +245,7 @@ public class KeyRotationTest extends AbstractKeycloakTest {
getCleanup().addComponentId(newId);
response.close();
- String updatedActiveKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get("RSA");
+ String updatedActiveKid = adminClient.realm("test").keys().getKeyMetadata().getActive().get(Algorithm.RS256);
assertNotEquals(activeKid, updatedActiveKid);
}
}
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java
index b2fdf8f..2ab996d 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/ApiUtil.java
@@ -16,8 +16,6 @@
*/
package org.keycloak.testsuite;
-import org.jboss.logging.Logger;
-
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@@ -29,8 +27,6 @@ import java.net.URI;
*/
public class ApiUtil {
- private static final Logger log = Logger.getLogger(ApiUtil.class);
-
public static String getCreatedId(Response response) {
URI location = response.getLocation();
if (!response.getStatusInfo().equals(Status.CREATED)) {
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 c13aecd..a062db2 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
@@ -1388,7 +1388,6 @@ authz-evaluation-authorization-data.tooltip=Represents a token carrying authoriz
authz-show-authorization-data=Show Authorization Data
keys=Keys
-all=All
status=Status
keystore=Keystore
keystores=Keystores
@@ -1396,6 +1395,10 @@ add-keystore=Add Keystore
add-keystore.placeholder=Add keystore...
view=View
active=Active
+passive=Passive
+disabled=Disabled
+algorithms=Algorithms
+providerHelpText=Provider description
Sunday=Sunday
Monday=Monday
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/app.js b/themes/src/main/resources/theme/base/admin/resources/js/app.js
index 6aaff54..f03208c 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -289,8 +289,8 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'RealmKeysCtrl'
})
- .when('/realms/:realm/keys/list', {
- templateUrl : resourceUrl + '/partials/realm-keys-list.html',
+ .when('/realms/:realm/keys/passive', {
+ templateUrl : resourceUrl + '/partials/realm-keys-passive.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
@@ -304,6 +304,21 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'RealmKeysCtrl'
})
+ .when('/realms/:realm/keys/disabled', {
+ templateUrl : resourceUrl + '/partials/realm-keys-disabled.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ serverInfo : function(ServerInfoLoader) {
+ return ServerInfoLoader();
+ },
+ keys: function(RealmKeysLoader) {
+ return RealmKeysLoader();
+ }
+ },
+ controller : 'RealmKeysCtrl'
+ })
.when('/realms/:realm/keys/providers', {
templateUrl : resourceUrl + '/partials/realm-keys-providers.html',
resolve : {
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html
index 81215d0..2bc75a8 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys.html
@@ -1,25 +1,61 @@
+<!--
+ ~ 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.
+ -->
+
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<kc-tabs-realm></kc-tabs-realm>
<ul class="nav nav-tabs nav-tabs-pf">
<li class="active"><a href="#/realms/{{realm.realm}}/keys">{{:: 'active' | translate}}</a></li>
- <li><a href="#/realms/{{realm.realm}}/keys/list">{{:: 'all' | translate}}</a></li>
+ <li><a href="#/realms/{{realm.realm}}/keys/passive">{{:: 'passive' | translate}}</a></li>
+ <li><a href="#/realms/{{realm.realm}}/keys/disabled">{{:: 'disabled' | translate}}</a></li>
<li><a href="#/realms/{{realm.realm}}/keys/providers">{{:: 'providers' | translate}}</a></li>
</ul>
<table class="table table-striped table-bordered">
<thead>
<tr>
+ <th class="kc-table-actions" colspan="7">
+ <div class="form-inline">
+ <div class="form-group">
+ <div class="input-group">
+ <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search" class="form-control search"">
+ <div class="input-group-addon">
+ <i class="fa fa-search"></i>
+ </div>
+ </div>
+ </div>
+ </div>
+ </th>
+ </tr>
+ <tr>
+ <th>{{:: 'algorithms' | translate}}</th>
<th>{{:: 'type' | translate}}</th>
<th>{{:: 'kid' | translate}}</th>
+ <th>{{:: 'priority' | translate}}</th>
<th>{{:: 'provider' | translate}}</th>
<th colspan="2">{{:: 'publicKeys' | translate}}</th>
</tr>
</thead>
<tbody>
- <tr ng-repeat="key in active">
+ <tr ng-repeat="key in keys | filter:search | filter:{status:'ACTIVE'}">
+ <td>{{key.algorithm.sort().join(', ')}}</td>
<td>{{key.type}}</td>
<td>{{key.kid}}</td>
+ <td>{{key.providerPriority}}</td>
<td><a href="#/realms/{{realm.realm}}/keys/providers/{{key.provider.providerId}}/{{key.provider.id}}">{{key.provider.name}}</a></td>
<td data-ng-show="key.type === 'RSA'" class="kc-action-cell" data-ng-click="viewKey(key.publicKey)">{{:: 'publicKey' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-passive.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-passive.html
new file mode 100755
index 0000000..461dcc1
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-passive.html
@@ -0,0 +1,71 @@
+<!--
+ ~ 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.
+ -->
+
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+ <kc-tabs-realm></kc-tabs-realm>
+
+ <ul class="nav nav-tabs nav-tabs-pf">
+ <li><a href="#/realms/{{realm.realm}}/keys">{{:: 'active' | translate}}</a></li>
+ <li class="active"><a href="#/realms/{{realm.realm}}/keys/passive">{{:: 'passive' | translate}}</a></li>
+ <li><a href="#/realms/{{realm.realm}}/keys/disabled">{{:: 'disabled' | translate}}</a></li>
+ <li><a href="#/realms/{{realm.realm}}/keys/providers">{{:: 'providers' | translate}}</a></li>
+ </ul>
+
+ <table class="table table-striped table-bordered">
+ <thead>
+ <tr>
+ <th class="kc-table-actions" colspan="7">
+ <div class="form-inline">
+ <div class="form-group">
+ <div class="input-group">
+ <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search" class="form-control search"">
+ <div class="input-group-addon">
+ <i class="fa fa-search"></i>
+ </div>
+ </div>
+ </div>
+ </div>
+ </th>
+ </tr>
+ <tr>
+ <th>{{:: 'algorithms' | translate}}</th>
+ <th>{{:: 'type' | translate}}</th>
+ <th>{{:: 'kid' | translate}}</th>
+ <th>{{:: 'priority' | translate}}</th>
+ <th>{{:: 'provider' | translate}}</th>
+ <th colspan="2">{{:: 'publicKeys' | translate}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="key in keys | filter:search | filter:{status:'PASSIVE'}">
+ <td>{{key.algorithm.sort().join(', ')}}</td>
+ <td>{{key.type}}</td>
+ <td>{{key.kid}}</td>
+ <td>{{key.providerPriority}}</td>
+ <td><a href="#/realms/{{realm.realm}}/keys/providers/{{key.provider.providerId}}/{{key.provider.id}}">{{key.provider.name}}</a></td>
+
+ <td data-ng-show="key.type === 'RSA'" class="kc-action-cell" data-ng-click="viewKey(key.publicKey)">{{:: 'publicKey' | translate}}</td>
+ <td data-ng-show="key.type === 'RSA'" class="kc-action-cell" data-ng-click="viewKey(key.certificate)">{{:: 'certificate' | translate}}</td>
+
+ <td data-ng-show="key.type !== 'RSA'" colspan="2"></td>
+ </tr>
+ </tbody>
+ </table>
+
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
index fceea49..c303a38 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-keys-providers.html
@@ -20,16 +20,26 @@
<ul class="nav nav-tabs nav-tabs-pf">
<li><a href="#/realms/{{realm.realm}}/keys">{{:: 'active' | translate}}</a></li>
- <li><a href="#/realms/{{realm.realm}}/keys/list">{{:: 'all' | translate}}</a></li>
+ <li><a href="#/realms/{{realm.realm}}/keys/passive">{{:: 'passive' | translate}}</a></li>
+ <li><a href="#/realms/{{realm.realm}}/keys/disabled">{{:: 'disabled' | translate}}</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/keys/providers">{{:: 'providers' | translate}}</a></li>
</ul>
<table class="table table-striped table-bordered">
<thead>
- <tr ng-show="providers.length > 0 && access.manageRealm">
- <th colspan="7" class="kc-table-actions">
- <div class="pull-right">
- <div>
+ <tr>
+ <th class="kc-table-actions" colspan="7">
+ <div class="form-inline">
+ <div class="form-group">
+ <div class="input-group">
+ <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search" class="form-control search">
+ <div class="input-group-addon">
+ <i class="fa fa-search"></i>
+ </div>
+ </div>
+ </div>
+
+ <div class="pull-right" data-ng-show="access.manageClients">
<select class="form-control" ng-model="selectedProvider"
ng-options="p.id for p in providers"
data-ng-change="addProvider(selectedProvider); selectedProvider = null">
@@ -40,20 +50,18 @@
</th>
</tr>
<tr data-ng-show="instances && instances.length > 0">
- <th>{{:: 'type' | translate}}</th>
<th>{{:: 'name' | translate}}</th>
- <th>{{:: 'id' | translate}}</th>
<th>{{:: 'provider' | translate}}</th>
+ <th>{{:: 'providerHelpText' | translate}}</th>
<th>{{:: 'priority' | translate}}</th>
<th colspan="2">{{:: 'actions' | translate}}</th>
</tr>
</thead>
<tbody>
- <tr ng-repeat="instance in instances">
- <td>{{instance.provider.metadata.algorithmType}}</td>
- <td>{{instance.name}}</td>
- <td><a href="#/realms/{{realm.realm}}/keys/providers/{{instance.providerId}}/{{instance.id}}">{{instance.id}}</a></td>
+ <tr ng-repeat="instance in instances | filter:search">
+ <td><a href="#/realms/{{realm.realm}}/keys/providers/{{instance.providerId}}/{{instance.id}}">{{instance.name}}</a></td>
<td>{{instance.providerId}}</td>
+ <td>{{instance.provider.helpText}}</td>
<td>{{instance.config['priority'][0]}}</td>
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/keys/providers/{{instance.providerId}}/{{instance.id}}">{{:: 'edit' | translate}}</td>
<td class="kc-action-cell" ng-show="instances.length > 1" data-ng-click="removeInstance(instance)">{{:: 'delete' | translate}}</td>