diff --git a/adapters/oidc/adapter-core/pom.xml b/adapters/oidc/adapter-core/pom.xml
index 0dd6a09a1ca..f206cedf85c 100755
--- a/adapters/oidc/adapter-core/pom.xml
+++ b/adapters/oidc/adapter-core/pom.xml
@@ -73,6 +73,10 @@
keycloak-core
provided
+
+ org.keycloak
+ ${keycloak.crypto.artifactId}
+
org.keycloak
keycloak-authz-client
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index af2a9610312..c83c0f073ff 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -25,7 +25,9 @@ import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator;
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.enums.SslRequired;
+import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.PemUtils;
import org.keycloak.enums.TokenStore;
import org.keycloak.representations.adapters.config.AdapterConfig;
@@ -181,6 +183,7 @@ public class KeycloakDeploymentBuilder {
}
public static KeycloakDeployment build(InputStream is) {
+ CryptoIntegration.init(KeycloakDeploymentBuilder.class.getClassLoader());
AdapterConfig adapterConfig = loadAdapterConfig(is);
return new KeycloakDeploymentBuilder().internalBuild(adapterConfig);
}
diff --git a/boms/adapter/pom.xml b/boms/adapter/pom.xml
index 33f9d04f355..91594eea972 100644
--- a/boms/adapter/pom.xml
+++ b/boms/adapter/pom.xml
@@ -44,6 +44,11 @@
keycloak-adapter-core
${project.version}
+
+ org.keycloak
+ keycloak-crypto-default
+ ${project.version}
+
org.keycloak
keycloak-adapter-spi
diff --git a/common/src/main/java/org/keycloak/common/crypto/CryptoIntegration.java b/common/src/main/java/org/keycloak/common/crypto/CryptoIntegration.java
new file mode 100644
index 00000000000..64afe01eb16
--- /dev/null
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoIntegration.java
@@ -0,0 +1,57 @@
+package org.keycloak.common.crypto;
+
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import org.jboss.logging.Logger;
+import org.keycloak.common.util.BouncyIntegration;
+
+/**
+ * @author Marek Posolda
+ */
+public class CryptoIntegration {
+
+ protected static final Logger logger = Logger.getLogger(CryptoIntegration.class);
+
+ private static final Object lock = new Object();
+ private static volatile CryptoProvider cryptoProvider;
+
+ public static void init(ClassLoader classLoader) {
+ if (cryptoProvider == null) {
+ synchronized (lock) {
+ if (cryptoProvider == null) {
+ cryptoProvider = detectProvider(classLoader);
+ logger.debugv("BouncyCastle provider: {0}", BouncyIntegration.PROVIDER);
+ }
+ }
+ }
+ }
+
+ public static CryptoProvider getProvider() {
+ if (cryptoProvider == null) {
+ throw new IllegalStateException("Illegal state. Please init first before obtaining provider");
+ }
+ return cryptoProvider;
+ }
+
+
+ // Try to auto-detect provider
+ private static CryptoProvider detectProvider(ClassLoader classLoader) {
+ List foundProviders = StreamSupport.stream(ServiceLoader.load(CryptoProvider.class, classLoader).spliterator(), false)
+ .collect(Collectors.toList());
+
+ if (foundProviders.isEmpty()) {
+ throw new IllegalStateException("Not able to load any cryptoProvider with the classLoader: " + classLoader);
+ } else if (foundProviders.size() > 1) {
+ throw new IllegalStateException("Multiple crypto providers loaded with the classLoader: " + classLoader +
+ ". Make sure only one cryptoProvider available on the classpath. Available providers: " +foundProviders);
+ } else {
+ logger.infof("Detected security provider: %s", foundProviders.get(0).getClass().getName());
+ return foundProviders.get(0);
+ }
+ }
+
+}
diff --git a/core/src/main/java/org/keycloak/crypto/integration/CryptoProvider.java b/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
similarity index 56%
rename from core/src/main/java/org/keycloak/crypto/integration/CryptoProvider.java
rename to common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
index 48694a346c3..7912a3ac2aa 100644
--- a/core/src/main/java/org/keycloak/crypto/integration/CryptoProvider.java
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
@@ -1,11 +1,9 @@
-package org.keycloak.crypto.integration;
+package org.keycloak.common.crypto;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
-import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
-
/**
* Abstraction to handle differences between the APIs for non-fips and fips mode
*
@@ -17,6 +15,14 @@ public interface CryptoProvider {
* @return secureRandom implementation based on the available security algorithms according to environment (FIPS non-fips)
*/
SecureRandom getSecureRandom() throws NoSuchAlgorithmException, NoSuchProviderException;
-
- JWEAlgorithmProvider getAesKeyWrapAlgorithmProvider();
+
+ /**
+ * Get some algorithm provider implementation. Returned implementation can be dependent according to if we have
+ * non-fips bouncycastle or fips bouncycastle on the classpath.
+ *
+ * @param clazz Returned class.
+ * @param algorithm Type of the algorithm, which we want to return
+ * @return
+ */
+ T getAlgorithmProvider(Class clazz, String algorithm);
}
diff --git a/common/src/main/java/org/keycloak/common/crypto/CryptoProviderTypes.java b/common/src/main/java/org/keycloak/common/crypto/CryptoProviderTypes.java
new file mode 100644
index 00000000000..0b9811f1ba1
--- /dev/null
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoProviderTypes.java
@@ -0,0 +1,11 @@
+package org.keycloak.common.crypto;
+
+/**
+ * @author Marek Posolda
+ */
+public class CryptoProviderTypes {
+
+ public static final String BC_SECURITY_PROVIDER = "bc-provider";
+
+ public static final String AES_KEY_WRAP_ALGORITHM_PROVIDER = "aes-keywrap-alg";
+}
diff --git a/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java b/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java
index b3f32d25cf0..4447a25f86b 100755
--- a/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java
+++ b/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java
@@ -18,8 +18,9 @@
package org.keycloak.common.util;
import org.jboss.logging.Logger;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoProviderTypes;
-import java.lang.reflect.Constructor;
import java.security.Provider;
import java.security.Security;
@@ -31,34 +32,20 @@ public class BouncyIntegration {
private static final Logger log = Logger.getLogger(BouncyIntegration.class);
- private static final String[] providerClassNames = {
- "org.bouncycastle.jce.provider.BouncyCastleProvider",
- "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider"
- };
-
public static final String PROVIDER = loadProvider();
private static String loadProvider() {
- for (String providerClassName : providerClassNames) {
- try {
- Class> providerClass = Class.forName(providerClassName, true, BouncyIntegration.class.getClassLoader());
- Constructor constructor = (Constructor) providerClass.getConstructor();
- Provider provider = constructor.newInstance();
-
- if (Security.getProvider(provider.getName()) == null) {
- Security.addProvider(provider);
- log.debugv("Loaded {0} security provider", providerClassName);
- } else {
- log.debugv("Security provider {0} already loaded", providerClassName);
- }
-
- return provider.getName();
- } catch (Exception e) {
- log.debugv("Failed to load {0}", e, providerClassName);
- }
+ Provider provider = CryptoIntegration.getProvider().getAlgorithmProvider(Provider.class, CryptoProviderTypes.BC_SECURITY_PROVIDER);
+ if (provider == null) {
+ throw new RuntimeException("Failed to load required security provider: BouncyCastleProvider or BouncyCastleFipsProvider");
}
-
- throw new RuntimeException("Failed to load required security provider: BouncyCastleProvider or BouncyCastleFipsProvider");
+ if (Security.getProvider(provider.getName()) == null) {
+ Security.addProvider(provider);
+ log.debugv("Loaded {0} security provider", provider.getClass().getName());
+ } else {
+ log.debugv("Security provider {0} already loaded", provider.getClass().getName());
+ }
+ return provider.getName();
}
}
diff --git a/core/pom.xml b/core/pom.xml
index 0ab99f34e44..1131a559fcb 100755
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -89,6 +89,13 @@
${project.build.outputDirectory}/META-INF/MANIFEST.MF
+
+
+
+ test-jar
+
+
+
org.apache.felix
diff --git a/core/src/main/java/org/keycloak/crypto/integration/CryptoIntegration.java b/core/src/main/java/org/keycloak/crypto/integration/CryptoIntegration.java
deleted file mode 100644
index 20bf664b1d2..00000000000
--- a/core/src/main/java/org/keycloak/crypto/integration/CryptoIntegration.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.keycloak.crypto.integration;
-
-import java.util.ServiceLoader;
-
-import org.jboss.logging.Logger;
-import org.keycloak.common.util.BouncyIntegration;
-
-/**
- * @author Marek Posolda
- */
-public class CryptoIntegration {
-
- protected static final Logger logger = Logger.getLogger(CryptoIntegration.class);
-
- private static volatile CryptoProvider securityProvider;
-
- public static CryptoProvider getProvider() {
- if (securityProvider == null) {
- logger.debugf("Using BouncyCastle provider: %s", BouncyIntegration.PROVIDER);
- securityProvider = detectProvider();
- logger.infof("Detected security provider: %s", securityProvider);
- }
- return securityProvider;
- }
-
-
- // This can be possibly set by the configuration (SPI) to override the "detected" instance
- public static void setProvider(CryptoProvider provider) {
- securityProvider = provider;
- }
-
-
- // Try to auto-detect provider
- private static CryptoProvider detectProvider() {
- // TODO This may not work on Wildfly (assuming FIPS module will be different Wildfly module than keycloak-core). May need to be improved (EG. with usage of org.keycloak.platform.Platform)
- for (CryptoProvider cryptoProvider : ServiceLoader.load(CryptoProvider.class, CryptoIntegration.class.getClassLoader())) {
- return cryptoProvider;
- }
- // Fallback. This should not be needed once DefaultCryptoProvider is moved into separate module like "crypto/default" and provided via ServiceLoader
- return new DefaultCryptoProvider();
- }
-
-}
diff --git a/core/src/main/java/org/keycloak/crypto/integration/DefaultCryptoProvider.java b/core/src/main/java/org/keycloak/crypto/integration/DefaultCryptoProvider.java
deleted file mode 100644
index bd2bc8c6a1b..00000000000
--- a/core/src/main/java/org/keycloak/crypto/integration/DefaultCryptoProvider.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.keycloak.crypto.integration;
-
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-
-import org.keycloak.jose.jwe.alg.AesKeyWrapAlgorithmProvider;
-import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
-
-/**
- * @author Marek Posolda
- */
-public class DefaultCryptoProvider implements CryptoProvider {
-
- @Override
- public SecureRandom getSecureRandom() throws NoSuchAlgorithmException {
- return SecureRandom.getInstance("SHA1PRNG");
- }
-
- @Override
- public JWEAlgorithmProvider getAesKeyWrapAlgorithmProvider() {
- return new AesKeyWrapAlgorithmProvider();
- }
-}
diff --git a/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java b/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java
index 5defa4df7c8..15f9e969e3f 100644
--- a/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java
+++ b/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java
@@ -20,7 +20,8 @@ package org.keycloak.jose.jwe;
import java.util.HashMap;
import java.util.Map;
-import org.keycloak.crypto.integration.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoProviderTypes;
import org.keycloak.jose.jwe.alg.DirectAlgorithmProvider;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
import org.keycloak.jose.jwe.alg.RsaKeyEncryption256JWEAlgorithmProvider;
@@ -47,7 +48,7 @@ class JWERegistry {
static {
// Provider 'dir' just directly uses encryption keys for encrypt/decrypt content.
ALG_PROVIDERS.put(JWEConstants.DIR, new DirectAlgorithmProvider());
- ALG_PROVIDERS.put(JWEConstants.A128KW, CryptoIntegration.getProvider().getAesKeyWrapAlgorithmProvider());
+ ALG_PROVIDERS.put(JWEConstants.A128KW, CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER));
ALG_PROVIDERS.put(JWEConstants.RSA_OAEP, new RsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"));
ALG_PROVIDERS.put(JWEConstants.RSA_OAEP_256, new RsaKeyEncryption256JWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"));
diff --git a/core/src/test/java/org/keycloak/KeyPairVerifierTest.java b/core/src/test/java/org/keycloak/KeyPairVerifierTest.java
index da76a611b9c..db1296d2d0f 100644
--- a/core/src/test/java/org/keycloak/KeyPairVerifierTest.java
+++ b/core/src/test/java/org/keycloak/KeyPairVerifierTest.java
@@ -18,13 +18,21 @@
package org.keycloak;
import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.keycloak.common.VerificationException;
+import org.keycloak.rule.CryptoInitRule;
/**
+ * This is not tested in keycloak-core. The subclasses should be created in the crypto modules to make sure it is tested with corresponding modules (bouncycastle VS bouncycastle-fips)
+ *
* @author Stian Thorgersen
*/
-public class KeyPairVerifierTest {
+public abstract class KeyPairVerifierTest {
+
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
String privateKey1 = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=";
String publicKey1 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
diff --git a/core/src/test/java/org/keycloak/jose/JWETest.java b/core/src/test/java/org/keycloak/jose/JWETest.java
index 918b59c617f..17918c9226e 100644
--- a/core/src/test/java/org/keycloak/jose/JWETest.java
+++ b/core/src/test/java/org/keycloak/jose/JWETest.java
@@ -25,7 +25,9 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.junit.Assert;
+import org.junit.ClassRule;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.Base64Url;
@@ -36,11 +38,17 @@ import org.keycloak.jose.jwe.alg.RsaKeyEncryptionJWEAlgorithmProvider;
import org.keycloak.jose.jwe.enc.AesCbcHmacShaJWEEncryptionProvider;
import org.keycloak.jose.jwe.enc.AesGcmJWEEncryptionProvider;
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
+import org.keycloak.rule.CryptoInitRule;
/**
+ * This is not tested in keycloak-core. The subclasses should be created in the crypto modules to make sure it is tested with corresponding modules (bouncycastle VS bouncycastle-fips)
+ *
* @author Marek Posolda
*/
-public class JWETest {
+public abstract class JWETest {
+
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
private static final String PAYLOAD = "Hello world! How are you man? I hope you are fine. This is some quite a long text, which is much longer than just simple 'Hello World'";
diff --git a/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java b/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java
index 1666e0dd265..3a7694f30b2 100644
--- a/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java
+++ b/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java
@@ -19,13 +19,17 @@ package org.keycloak.jose.jwk;
import java.util.Arrays;
import java.util.List;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.crypto.JavaAlgorithm;
-import org.keycloak.crypto.integration.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.rule.CryptoInitRule;
import org.keycloak.util.JsonSerialization;
import java.nio.charset.StandardCharsets;
@@ -47,9 +51,14 @@ import static org.junit.Assert.assertTrue;
import static org.keycloak.common.util.CertificateUtils.generateV1SelfSignedCertificate;
/**
+ * This is not tested in keycloak-core. The subclasses should be created in the crypto modules to make sure it is tested with corresponding modules (bouncycastle VS bouncycastle-fips)
+ *
* @author Stian Thorgersen
*/
-public class JWKTest {
+public abstract class JWKTest {
+
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
@Test
public void publicRs256() throws Exception {
diff --git a/core/src/test/java/org/keycloak/rule/CryptoInitRule.java b/core/src/test/java/org/keycloak/rule/CryptoInitRule.java
new file mode 100644
index 00000000000..cfd63c155a7
--- /dev/null
+++ b/core/src/test/java/org/keycloak/rule/CryptoInitRule.java
@@ -0,0 +1,16 @@
+package org.keycloak.rule;
+
+import org.junit.rules.ExternalResource;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoProvider;
+
+/**
+ * @author Marek Posolda
+ */
+public class CryptoInitRule extends ExternalResource {
+
+ @Override
+ protected void before() throws Throwable {
+ CryptoIntegration.init(CryptoProvider.class.getClassLoader());
+ }
+}
diff --git a/crypto/default/pom.xml b/crypto/default/pom.xml
new file mode 100644
index 00000000000..217bad4cdb4
--- /dev/null
+++ b/crypto/default/pom.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+ keycloak-crypto-parent
+ org.keycloak
+ 999-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ keycloak-crypto-default
+ Keycloak Crypto Default
+
+
+
+
+ org.keycloak
+ keycloak-core
+
+
+ org.keycloak
+ keycloak-core
+ test
+ test-jar
+
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+
+
+ org.jboss.logging
+ jboss-logging
+ provided
+
+
+ junit
+ junit
+ test
+
+
+ org.hamcrest
+ hamcrest
+ test
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/java/org/keycloak/jose/jwe/alg/AesKeyWrapAlgorithmProvider.java b/crypto/default/src/main/java/org/keycloak/crypto/def/AesKeyWrapAlgorithmProvider.java
similarity index 95%
rename from core/src/main/java/org/keycloak/jose/jwe/alg/AesKeyWrapAlgorithmProvider.java
rename to crypto/default/src/main/java/org/keycloak/crypto/def/AesKeyWrapAlgorithmProvider.java
index 24fe6342774..36fb50b8caa 100644
--- a/core/src/main/java/org/keycloak/jose/jwe/alg/AesKeyWrapAlgorithmProvider.java
+++ b/crypto/default/src/main/java/org/keycloak/crypto/def/AesKeyWrapAlgorithmProvider.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.keycloak.jose.jwe.alg;
+package org.keycloak.crypto.def;
import java.security.Key;
@@ -23,6 +23,7 @@ import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.engines.AESWrapEngine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.keycloak.jose.jwe.JWEKeyStorage;
+import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
/**
diff --git a/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java
new file mode 100644
index 00000000000..765a8941b11
--- /dev/null
+++ b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java
@@ -0,0 +1,38 @@
+package org.keycloak.crypto.def;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.keycloak.common.crypto.CryptoProvider;
+import org.keycloak.common.crypto.CryptoProviderTypes;
+
+/**
+ * @author Marek Posolda
+ */
+public class DefaultCryptoProvider implements CryptoProvider {
+
+ private Map> providers = new HashMap<>();
+
+ public DefaultCryptoProvider() {
+ providers.put(CryptoProviderTypes.BC_SECURITY_PROVIDER, BouncyCastleProvider::new);
+ providers.put(CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER, AesKeyWrapAlgorithmProvider::new);
+ }
+
+ @Override
+ public SecureRandom getSecureRandom() throws NoSuchAlgorithmException {
+ return SecureRandom.getInstance("SHA1PRNG");
+ }
+
+ @Override
+ public T getAlgorithmProvider(Class clazz, String algorithm) {
+ Object o = providers.get(algorithm).get();
+ if (o == null) {
+ throw new IllegalArgumentException("Not found provider of algorithm: " + algorithm);
+ }
+ return clazz.cast(o);
+ }
+}
diff --git a/crypto/default/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider b/crypto/default/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider
new file mode 100644
index 00000000000..2f16ff81547
--- /dev/null
+++ b/crypto/default/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider
@@ -0,0 +1,18 @@
+#
+# Copyright 2022 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.
+#
+
+org.keycloak.crypto.def.DefaultCryptoProvider
\ No newline at end of file
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWETest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWETest.java
new file mode 100644
index 00000000000..e75dbfb7f50
--- /dev/null
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWETest.java
@@ -0,0 +1,11 @@
+package org.keycloak.crypto.def.test;
+
+import org.keycloak.jose.JWETest;
+
+/**
+ * Test with default security provider and non-fips bouncycastle
+ *
+ * @author Marek Posolda
+ */
+public class DefaultCryptoJWETest extends JWETest {
+}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWKTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWKTest.java
new file mode 100644
index 00000000000..4ba6456e5ea
--- /dev/null
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWKTest.java
@@ -0,0 +1,11 @@
+package org.keycloak.crypto.def.test;
+
+import org.keycloak.jose.jwk.JWKTest;
+
+/**
+ * Test with default security provider and non-fips bouncycastle
+ *
+ * @author Marek Posolda
+ */
+public class DefaultCryptoJWKTest extends JWKTest {
+}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoKeyPairVerifierTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoKeyPairVerifierTest.java
new file mode 100644
index 00000000000..1b0e005fc3c
--- /dev/null
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoKeyPairVerifierTest.java
@@ -0,0 +1,11 @@
+package org.keycloak.crypto.def.test;
+
+import org.keycloak.KeyPairVerifierTest;
+
+/**
+ * Test with default security provider and non-fips bouncycastle
+ *
+ * @author Marek Posolda
+ */
+public class DefaultCryptoKeyPairVerifierTest extends KeyPairVerifierTest {
+}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoUnitTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoUnitTest.java
new file mode 100644
index 00000000000..907ab0a32c0
--- /dev/null
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoUnitTest.java
@@ -0,0 +1,20 @@
+package org.keycloak.crypto.def.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoProviderTypes;
+import org.keycloak.crypto.def.AesKeyWrapAlgorithmProvider;
+import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
+
+/**
+ * @author Marek Posolda
+ */
+public class DefaultCryptoUnitTest {
+
+ @Test
+ public void testDefaultCrypto() throws Exception {
+ JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER);
+ Assert.assertEquals(jweAlg.getClass(), AesKeyWrapAlgorithmProvider.class);
+ }
+}
diff --git a/crypto/fips1402/pom.xml b/crypto/fips1402/pom.xml
index fd38706245e..0373eef80df 100644
--- a/crypto/fips1402/pom.xml
+++ b/crypto/fips1402/pom.xml
@@ -26,14 +26,32 @@
4.0.0
- keycloak-fips1402
- Keycloak FIPS 140-2 Integration
+ keycloak-crypto-fips1402
+ Keycloak Crypto FIPS 140-2 Integration
org.keycloak
keycloak-core
+
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+
+
+
+
+ org.keycloak
+ keycloak-core
+ test
+ test-jar
+
org.bouncycastle
diff --git a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java
index 481af1737e5..5e8c848a896 100644
--- a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java
+++ b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java
@@ -3,9 +3,13 @@ package org.keycloak.crypto.fips;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
-import org.keycloak.crypto.integration.CryptoProvider;
-import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
+import org.keycloak.common.crypto.CryptoProvider;
+import org.keycloak.common.crypto.CryptoProviderTypes;
/**
@@ -15,13 +19,24 @@ import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
*/
public class FIPS1402Provider implements CryptoProvider {
+ private Map> providers = new HashMap<>();
+
+ public FIPS1402Provider() {
+ providers.put(CryptoProviderTypes.BC_SECURITY_PROVIDER, BouncyCastleFipsProvider::new);
+ providers.put(CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER, FIPSAesKeyWrapAlgorithmProvider::new);
+ }
+
@Override
public SecureRandom getSecureRandom() throws NoSuchAlgorithmException, NoSuchProviderException {
return SecureRandom.getInstance("DEFAULT","BCFIPS");
}
@Override
- public JWEAlgorithmProvider getAesKeyWrapAlgorithmProvider() {
- return new FIPSAesKeyWrapAlgorithmProvider();
+ public T getAlgorithmProvider(Class clazz, String algorithm) {
+ Object o = providers.get(algorithm).get();
+ if (o == null) {
+ throw new IllegalArgumentException("Not found provider of algorithm: " + algorithm);
+ }
+ return clazz.cast(o);
}
}
diff --git a/crypto/fips1402/src/main/resources/META-INF/services/org.keycloak.crypto.integration.CryptoProvider b/crypto/fips1402/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider
similarity index 100%
rename from crypto/fips1402/src/main/resources/META-INF/services/org.keycloak.crypto.integration.CryptoProvider
rename to crypto/fips1402/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402JWETest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402JWETest.java
new file mode 100644
index 00000000000..802e85b548a
--- /dev/null
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402JWETest.java
@@ -0,0 +1,13 @@
+package org.keycloak.crypto.fips.test;
+
+import org.junit.Ignore;
+import org.keycloak.jose.JWETest;
+
+/**
+ * Test with fips1402 security provider and bouncycastle-fips
+ *
+ * @author Marek Posolda
+ */
+@Ignore("Ignored by default as it does not work on non-fips enabled environment") // TODO: Figure how to test in the FIPS environments, but still keep disabled in the non-FIPS environments
+public class FIPS1402JWETest extends JWETest {
+}
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402JWKTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402JWKTest.java
new file mode 100644
index 00000000000..182ef0f7da0
--- /dev/null
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402JWKTest.java
@@ -0,0 +1,13 @@
+package org.keycloak.crypto.fips.test;
+
+import org.junit.Ignore;
+import org.keycloak.jose.jwk.JWKTest;
+
+/**
+ * Test with fips1402 security provider and bouncycastle-fips
+ *
+ * @author Marek Posolda
+ */
+@Ignore("Ignored by default as it does not work on non-fips enabled environment") // TODO: Figure how to test in the FIPS environments, but still keep disabled in the non-FIPS environments
+public class FIPS1402JWKTest extends JWKTest {
+}
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402KeyPairVerifierTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402KeyPairVerifierTest.java
new file mode 100644
index 00000000000..412234ffe35
--- /dev/null
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402KeyPairVerifierTest.java
@@ -0,0 +1,13 @@
+package org.keycloak.crypto.fips.test;
+
+import org.junit.Ignore;
+import org.keycloak.KeyPairVerifierTest;
+
+/**
+ * Test with fips1402 security provider and bouncycastle-fips
+ *
+ * @author Marek Posolda
+ */
+@Ignore("Ignored by default as it does not work on non-fips enabled environment") // TODO: Figure how to test in the FIPS environments, but still keep disabled in the non-FIPS environments
+public class FIPS1402KeyPairVerifierTest extends KeyPairVerifierTest {
+}
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java
index 3798ebb27de..2d6336e6d86 100644
--- a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java
@@ -1,25 +1,26 @@
package org.keycloak.crypto.fips.test;
-import java.security.SecureRandom;
-
import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
+import org.keycloak.common.crypto.CryptoProviderTypes;
import org.keycloak.crypto.fips.FIPSAesKeyWrapAlgorithmProvider;
-import org.keycloak.crypto.integration.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
+import org.keycloak.rule.CryptoInitRule;
/**
* @author Marek Posolda
*/
public class FIPS1402UnitTest {
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
@Test
public void testFips() throws Exception {
- JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAesKeyWrapAlgorithmProvider();
+ JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER);
Assert.assertEquals(jweAlg.getClass(), FIPSAesKeyWrapAlgorithmProvider.class);
-
- SecureRandom scr = CryptoIntegration.getProvider().getSecureRandom();
- Assert.assertEquals("BCFIPS", scr.getProvider().getName());
}
}
diff --git a/crypto/pom.xml b/crypto/pom.xml
index 2881a99f947..077717570e1 100644
--- a/crypto/pom.xml
+++ b/crypto/pom.xml
@@ -32,5 +32,6 @@
fips1402
+ default
\ No newline at end of file
diff --git a/distribution/feature-packs/adapter-feature-pack/pom.xml b/distribution/feature-packs/adapter-feature-pack/pom.xml
index bcaa41d59cc..fac3f881553 100755
--- a/distribution/feature-packs/adapter-feature-pack/pom.xml
+++ b/distribution/feature-packs/adapter-feature-pack/pom.xml
@@ -58,6 +58,16 @@
+
+ org.keycloak
+ keycloak-crypto-default
+
+
+ *
+ *
+
+
+
org.keycloak
keycloak-adapter-core
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml
index 14203f90802..1d89bc9e490 100755
--- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-adapter-core/main/module.xml
@@ -34,6 +34,7 @@
+
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml
new file mode 100644
index 00000000000..afcabe3cc9f
--- /dev/null
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/feature-packs/server-feature-pack-dependencies/pom.xml b/distribution/feature-packs/server-feature-pack-dependencies/pom.xml
index a628c1df17a..97a4e627fe3 100644
--- a/distribution/feature-packs/server-feature-pack-dependencies/pom.xml
+++ b/distribution/feature-packs/server-feature-pack-dependencies/pom.xml
@@ -140,6 +140,16 @@
+
+ org.keycloak
+ keycloak-crypto-default
+
+
+ *
+ *
+
+
+
org.keycloak
keycloak-js-adapter
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml
new file mode 100644
index 00000000000..8cbcac41aac
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index 97340bedca7..f684415ff78 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -27,6 +27,7 @@
+
diff --git a/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml
new file mode 100644
index 00000000000..8cbcac41aac
--- /dev/null
+++ b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index 97340bedca7..f684415ff78 100755
--- a/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -27,6 +27,7 @@
+
diff --git a/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml
index 88548016561..4b4e42ffd0c 100755
--- a/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml
+++ b/distribution/galleon-feature-packs/server-galleon-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-adduser/main/module.xml
@@ -29,6 +29,7 @@
+
diff --git a/docs/fips.md b/docs/fips.md
index 1f0d061927a..ed97e6d82c2 100644
--- a/docs/fips.md
+++ b/docs/fips.md
@@ -10,7 +10,10 @@ With OpenJDK 11 on the classpath, run this from the project root directory:
mvn clean install -DskipTests=true -Dfips140-2 -Pquarkus
```
The property `fips140-2` is used to trigger maven profile to build keycloak+quarkus distribution with `bouncycastle-fips` dependencies instead of plain `bouncycastle`
-and also with `keycloak-fips140-2` module containing some security code dependent on bouncycastle-fips APIs.
+and also with `keycloak-crypto-fips1402` module containing some security code dependent on bouncycastle-fips APIs.
+
+Note, that if you ommit the `fips140-2` property from the command above, then the quarkus distribution will be built
+with the plain non-fips bouncycastle dependencies and with `keycloak-crypto-default` module.
Then unzip and check only bouncycastle-fips libraries are inside "lib" directory:
```
diff --git a/pom.xml b/pom.xml
index d7901ef7e2e..1d35863576b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1057,6 +1057,12 @@
keycloak-core
${project.version}
+
+ org.keycloak
+ keycloak-core
+ test-jar
+ ${project.version}
+
org.keycloak
keycloak-config-api
@@ -1600,7 +1606,12 @@
org.keycloak
- keycloak-fips1402
+ keycloak-crypto-default
+ ${project.version}
+
+
+ org.keycloak
+ keycloak-crypto-fips1402
${project.version}
@@ -2124,5 +2135,29 @@
+
+ crypto-default
+
+
+ !fips140-2
+
+
+
+ keycloak-crypto-default
+
+
+
+
+ fips140-2
+
+
+ fips140-2
+
+
+
+ keycloak-crypto-fips1402
+
+
+
diff --git a/quarkus/runtime/pom.xml b/quarkus/runtime/pom.xml
index 23fa53ed9f1..d42161a8ee5 100644
--- a/quarkus/runtime/pom.xml
+++ b/quarkus/runtime/pom.xml
@@ -141,6 +141,10 @@
+
+ org.keycloak
+ ${keycloak.crypto.artifactId}
+
org.keycloak
keycloak-server-spi
@@ -593,52 +597,6 @@
-
-
- crypto-default
-
-
- !fips140-2
-
-
-
-
- org.bouncycastle
- bcpkix-jdk15on
-
-
- *
- *
-
-
-
-
- org.bouncycastle
- bcprov-jdk15on
-
-
- *
- *
-
-
-
-
-
-
-
- fips140-2
-
-
- fips140-2
-
-
-
-
- org.keycloak
- keycloak-fips1402
-
-
-
diff --git a/saml-core/pom.xml b/saml-core/pom.xml
index 7f17007259c..75a40c9528a 100755
--- a/saml-core/pom.xml
+++ b/saml-core/pom.xml
@@ -54,6 +54,11 @@
org.apache.santuario
xmlsec
+
+ org.keycloak
+ ${keycloak.crypto.artifactId}
+ test
+
junit
junit
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
index 5f7770e0669..accb35b62ab 100644
--- a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
@@ -19,9 +19,12 @@ package org.keycloak.saml.processing.core.parsers.saml;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.DerUtils;
import org.keycloak.common.util.StreamUtil;
@@ -128,6 +131,11 @@ public class SAMLParserTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
+ @BeforeClass
+ public static void initCrypto() {
+ CryptoIntegration.init(CryptoProvider.class.getClassLoader());
+ }
+
@Before
public void initParser() {
this.parser = SAMLParser.getInstance();
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
index 7155bb30486..a4310bf7c73 100644
--- a/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
@@ -20,7 +20,11 @@ import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.Arrays;
+import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.DerUtils;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
@@ -40,6 +44,11 @@ public class AssertionUtilTest {
*/
private static final String PUBLIC_CERT = "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin";
+ @BeforeClass
+ public static void initCrypto() {
+ CryptoIntegration.init(CryptoProvider.class.getClassLoader());
+ }
+
@Test
public void testSaml20Signed() throws Exception {
diff --git a/services/pom.xml b/services/pom.xml
index 3e1e4fcb646..5110042cba1 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -47,6 +47,17 @@
org.keycloak
keycloak-core
+
+ org.keycloak
+ keycloak-core
+ test
+ test-jar
+
+
+ org.keycloak
+ ${keycloak.crypto.artifactId}
+ test
+
org.freemarker
freemarker
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 7cb6993819a..c13e1eb52de 100644
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -19,6 +19,8 @@ package org.keycloak.services.resources;
import com.fasterxml.jackson.core.type.TypeReference;
import org.jboss.logging.Logger;
import org.keycloak.Config;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.Resteasy;
import org.keycloak.config.ConfigProviderFactory;
import org.keycloak.exportimport.ExportImportManager;
@@ -90,6 +92,7 @@ public class KeycloakApplication extends Application {
logger.debugv("PlatformProvider: {0}", platform.getClass().getName());
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
+ CryptoIntegration.init(KeycloakApplication.class.getClassLoader());
loadConfig();
diff --git a/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificatePemIdentityExtractorTest.java b/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificatePemIdentityExtractorTest.java
index bc5df5ea78b..b0cab146a21 100644
--- a/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificatePemIdentityExtractorTest.java
+++ b/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificatePemIdentityExtractorTest.java
@@ -6,12 +6,17 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.cert.X509Certificate;
+import org.junit.ClassRule;
+import org.keycloak.rule.CryptoInitRule;
import org.junit.Test;
import org.keycloak.common.util.PemUtils;
import org.keycloak.common.util.StreamUtil;
public class CertificatePemIdentityExtractorTest {
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
+
@Test
public void testExtractsCertInPemFormat() throws Exception {
InputStream is = getClass().getResourceAsStream("/certs/UPN-cert.pem");
diff --git a/services/src/test/java/org/keycloak/authentication/authenticators/x509/SubjectAltNameIdentityExtractorTest.java b/services/src/test/java/org/keycloak/authentication/authenticators/x509/SubjectAltNameIdentityExtractorTest.java
index c03a54d56a8..8052d3b16d2 100644
--- a/services/src/test/java/org/keycloak/authentication/authenticators/x509/SubjectAltNameIdentityExtractorTest.java
+++ b/services/src/test/java/org/keycloak/authentication/authenticators/x509/SubjectAltNameIdentityExtractorTest.java
@@ -21,15 +21,20 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.cert.X509Certificate;
import org.junit.Assert;
+import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.util.PemUtils;
import org.keycloak.common.util.StreamUtil;
+import org.keycloak.rule.CryptoInitRule;
/**
* @author Marek Posolda
*/
public class SubjectAltNameIdentityExtractorTest {
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
+
@Test
public void testX509SubjectAltName_otherName() throws Exception {
UserIdentityExtractor extractor = UserIdentityExtractor.getSubjectAltNameExtractor(0);
diff --git a/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java b/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java
index 7207b1fbc4c..d007be5dbc4 100644
--- a/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java
+++ b/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java
@@ -32,14 +32,19 @@ import javax.ws.rs.core.Response;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.protocol.docker.installation.DockerComposeYamlInstallationProvider;
+import org.keycloak.rule.CryptoInitRule;
public class DockerComposeYamlInstallationProviderTest {
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
+
DockerComposeYamlInstallationProvider installationProvider;
static Certificate certificate;
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/CryptoInitRule.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/CryptoInitRule.java
new file mode 100644
index 00000000000..a818ffe47d3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/CryptoInitRule.java
@@ -0,0 +1,16 @@
+package org.keycloak.testsuite.util;
+
+import org.junit.rules.ExternalResource;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.crypto.CryptoProvider;
+
+/**
+ * @author Marek Posolda
+ */
+public class CryptoInitRule extends ExternalResource {
+
+ @Override
+ protected void before() throws Throwable {
+ CryptoIntegration.init(CryptoProvider.class.getClassLoader());
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
index 16b32dbefd8..4c36e24a4a1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -26,6 +26,7 @@ import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.logging.Logger;
import org.junit.After;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.runner.RunWith;
import org.junit.runners.model.TestTimedOutException;
import org.keycloak.admin.client.Keycloak;
@@ -59,6 +60,7 @@ import org.keycloak.testsuite.auth.page.login.OIDCLogin;
import org.keycloak.testsuite.auth.page.login.UpdatePassword;
import org.keycloak.testsuite.client.KeycloakTestingClient;
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
+import org.keycloak.testsuite.util.CryptoInitRule;
import org.keycloak.testsuite.util.DroneUtils;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.TestCleanup;
@@ -109,6 +111,9 @@ public abstract class AbstractKeycloakTest {
protected Logger log = Logger.getLogger(this.getClass());
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
+
@ArquillianResource
protected SuiteContext suiteContext;
diff --git a/testsuite/utils/pom.xml b/testsuite/utils/pom.xml
index 8f345ccc92d..61d2cc35b27 100755
--- a/testsuite/utils/pom.xml
+++ b/testsuite/utils/pom.xml
@@ -129,6 +129,10 @@
org.keycloak
keycloak-server-spi-private
+
+ org.keycloak
+ ${keycloak.crypto.artifactId}
+
org.keycloak
keycloak-ldap-federation
diff --git a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
index f373730915c..e2113a56ba5 100644
--- a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
+++ b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java
@@ -29,8 +29,7 @@ import org.aesh.command.invocation.CommandInvocation;
import org.aesh.command.impl.registry.AeshCommandRegistryBuilder;
import org.aesh.command.registry.CommandRegistry;
import org.aesh.command.registry.CommandRegistryException;
-import org.keycloak.common.util.Base64;
-import org.keycloak.credential.CredentialModel;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.credential.hash.PasswordHashProvider;
import org.keycloak.credential.hash.PasswordHashProviderFactory;
import org.keycloak.models.PasswordPolicy;
@@ -108,6 +107,8 @@ public class AddUser {
File addUserFile = getAddUserFile(this);
+ CryptoIntegration.init(AddUser.class.getClassLoader());
+
createUser(addUserFile, realm, user, password, roles, iterations);
}
} catch (Exception e){