Introduce crypto/default module. Refactoring BouncyIntegration (#12692)
Closes #12625
This commit is contained in:
parent
91335ebaad
commit
be1e31dc68
55 changed files with 685 additions and 166 deletions
|
@ -73,6 +73,10 @@
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>${keycloak.crypto.artifactId}</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-authz-client</artifactId>
|
<artifactId>keycloak-authz-client</artifactId>
|
||||||
|
|
|
@ -25,7 +25,9 @@ import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||||
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
import org.keycloak.adapters.authorization.PolicyEnforcer;
|
||||||
import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator;
|
import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator;
|
||||||
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
|
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
|
||||||
|
import org.keycloak.common.crypto.CryptoIntegration;
|
||||||
import org.keycloak.common.enums.SslRequired;
|
import org.keycloak.common.enums.SslRequired;
|
||||||
|
import org.keycloak.common.util.BouncyIntegration;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.enums.TokenStore;
|
import org.keycloak.enums.TokenStore;
|
||||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
|
@ -181,6 +183,7 @@ public class KeycloakDeploymentBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static KeycloakDeployment build(InputStream is) {
|
public static KeycloakDeployment build(InputStream is) {
|
||||||
|
CryptoIntegration.init(KeycloakDeploymentBuilder.class.getClassLoader());
|
||||||
AdapterConfig adapterConfig = loadAdapterConfig(is);
|
AdapterConfig adapterConfig = loadAdapterConfig(is);
|
||||||
return new KeycloakDeploymentBuilder().internalBuild(adapterConfig);
|
return new KeycloakDeploymentBuilder().internalBuild(adapterConfig);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,11 @@
|
||||||
<artifactId>keycloak-adapter-core</artifactId>
|
<artifactId>keycloak-adapter-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-crypto-default</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-adapter-spi</artifactId>
|
<artifactId>keycloak-adapter-spi</artifactId>
|
||||||
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
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<CryptoProvider> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
package org.keycloak.crypto.integration;
|
package org.keycloak.common.crypto;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstraction to handle differences between the APIs for non-fips and fips mode
|
* Abstraction to handle differences between the APIs for non-fips and fips mode
|
||||||
*
|
*
|
||||||
|
@ -18,5 +16,13 @@ public interface CryptoProvider {
|
||||||
*/
|
*/
|
||||||
SecureRandom getSecureRandom() throws NoSuchAlgorithmException, NoSuchProviderException;
|
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> T getAlgorithmProvider(Class<T> clazz, String algorithm);
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package org.keycloak.common.crypto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class CryptoProviderTypes {
|
||||||
|
|
||||||
|
public static final String BC_SECURITY_PROVIDER = "bc-provider";
|
||||||
|
|
||||||
|
public static final String AES_KEY_WRAP_ALGORITHM_PROVIDER = "aes-keywrap-alg";
|
||||||
|
}
|
|
@ -18,8 +18,9 @@
|
||||||
package org.keycloak.common.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
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.Provider;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
|
||||||
|
@ -31,34 +32,20 @@ public class BouncyIntegration {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(BouncyIntegration.class);
|
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();
|
public static final String PROVIDER = loadProvider();
|
||||||
|
|
||||||
private static String loadProvider() {
|
private static String loadProvider() {
|
||||||
for (String providerClassName : providerClassNames) {
|
Provider provider = CryptoIntegration.getProvider().getAlgorithmProvider(Provider.class, CryptoProviderTypes.BC_SECURITY_PROVIDER);
|
||||||
try {
|
if (provider == null) {
|
||||||
Class<?> providerClass = Class.forName(providerClassName, true, BouncyIntegration.class.getClassLoader());
|
|
||||||
Constructor<Provider> constructor = (Constructor<Provider>) 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,13 @@
|
||||||
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>test-jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.felix</groupId>
|
<groupId>org.apache.felix</groupId>
|
||||||
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class DefaultCryptoProvider implements CryptoProvider {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SecureRandom getSecureRandom() throws NoSuchAlgorithmException {
|
|
||||||
return SecureRandom.getInstance("SHA1PRNG");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JWEAlgorithmProvider getAesKeyWrapAlgorithmProvider() {
|
|
||||||
return new AesKeyWrapAlgorithmProvider();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,7 +20,8 @@ package org.keycloak.jose.jwe;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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.DirectAlgorithmProvider;
|
||||||
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
|
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
|
||||||
import org.keycloak.jose.jwe.alg.RsaKeyEncryption256JWEAlgorithmProvider;
|
import org.keycloak.jose.jwe.alg.RsaKeyEncryption256JWEAlgorithmProvider;
|
||||||
|
@ -47,7 +48,7 @@ class JWERegistry {
|
||||||
static {
|
static {
|
||||||
// Provider 'dir' just directly uses encryption keys for encrypt/decrypt content.
|
// Provider 'dir' just directly uses encryption keys for encrypt/decrypt content.
|
||||||
ALG_PROVIDERS.put(JWEConstants.DIR, new DirectAlgorithmProvider());
|
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, new RsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"));
|
||||||
ALG_PROVIDERS.put(JWEConstants.RSA_OAEP_256, new RsaKeyEncryption256JWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"));
|
ALG_PROVIDERS.put(JWEConstants.RSA_OAEP_256, new RsaKeyEncryption256JWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"));
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,21 @@
|
||||||
package org.keycloak;
|
package org.keycloak;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.VerificationException;
|
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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
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 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";
|
String publicKey1 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
|
||||||
|
|
|
@ -25,7 +25,9 @@ import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.ClassRule;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.util.Base64;
|
import org.keycloak.common.util.Base64;
|
||||||
import org.keycloak.common.util.Base64Url;
|
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.AesCbcHmacShaJWEEncryptionProvider;
|
||||||
import org.keycloak.jose.jwe.enc.AesGcmJWEEncryptionProvider;
|
import org.keycloak.jose.jwe.enc.AesGcmJWEEncryptionProvider;
|
||||||
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
|
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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
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'";
|
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'";
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,17 @@ package org.keycloak.jose.jwk;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.util.Base64Url;
|
import org.keycloak.common.util.Base64Url;
|
||||||
import org.keycloak.common.util.BouncyIntegration;
|
import org.keycloak.common.util.BouncyIntegration;
|
||||||
import org.keycloak.common.util.KeyUtils;
|
import org.keycloak.common.util.KeyUtils;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.crypto.JavaAlgorithm;
|
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 org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -47,9 +51,14 @@ import static org.junit.Assert.assertTrue;
|
||||||
import static org.keycloak.common.util.CertificateUtils.generateV1SelfSignedCertificate;
|
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 <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class JWKTest {
|
public abstract class JWKTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publicRs256() throws Exception {
|
public void publicRs256() throws Exception {
|
||||||
|
|
16
core/src/test/java/org/keycloak/rule/CryptoInitRule.java
Normal file
16
core/src/test/java/org/keycloak/rule/CryptoInitRule.java
Normal file
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class CryptoInitRule extends ExternalResource {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void before() throws Throwable {
|
||||||
|
CryptoIntegration.init(CryptoProvider.class.getClassLoader());
|
||||||
|
}
|
||||||
|
}
|
70
crypto/default/pom.xml
Normal file
70
crypto/default/pom.xml
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-crypto-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>999-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>keycloak-crypto-default</artifactId>
|
||||||
|
<name>Keycloak Crypto Default</name>
|
||||||
|
<description/>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<type>test-jar</type>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.jose.jwe.alg;
|
package org.keycloak.crypto.def;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import org.bouncycastle.crypto.Wrapper;
|
||||||
import org.bouncycastle.crypto.engines.AESWrapEngine;
|
import org.bouncycastle.crypto.engines.AESWrapEngine;
|
||||||
import org.bouncycastle.crypto.params.KeyParameter;
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
import org.keycloak.jose.jwe.JWEKeyStorage;
|
import org.keycloak.jose.jwe.JWEKeyStorage;
|
||||||
|
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
|
||||||
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
|
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class DefaultCryptoProvider implements CryptoProvider {
|
||||||
|
|
||||||
|
private Map<String, Supplier<?>> 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> T getAlgorithmProvider(Class<T> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class DefaultCryptoJWETest extends JWETest {
|
||||||
|
}
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class DefaultCryptoJWKTest extends JWKTest {
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package org.keycloak.crypto.def.test;
|
||||||
|
|
||||||
|
import org.keycloak.KeyPairVerifierTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test with default security provider and non-fips bouncycastle
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class DefaultCryptoKeyPairVerifierTest extends KeyPairVerifierTest {
|
||||||
|
}
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,14 +26,32 @@
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-fips1402</artifactId>
|
<artifactId>keycloak-crypto-fips1402</artifactId>
|
||||||
<name>Keycloak FIPS 140-2 Integration</name>
|
<name>Keycloak Crypto FIPS 140-2 Integration</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<!-- TODO: These exclusions can be removed once we remove dependency of keycloak-core on bouncycastle -->
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<!-- TODO: These exclusions can be removed once we remove dependency of keycloak-core on bouncycastle -->
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>org.bouncycastle</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
|
|
@ -3,9 +3,13 @@ package org.keycloak.crypto.fips;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.SecureRandom;
|
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.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
|
||||||
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
|
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 {
|
public class FIPS1402Provider implements CryptoProvider {
|
||||||
|
|
||||||
|
private Map<String, Supplier<?>> providers = new HashMap<>();
|
||||||
|
|
||||||
|
public FIPS1402Provider() {
|
||||||
|
providers.put(CryptoProviderTypes.BC_SECURITY_PROVIDER, BouncyCastleFipsProvider::new);
|
||||||
|
providers.put(CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER, FIPSAesKeyWrapAlgorithmProvider::new);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecureRandom getSecureRandom() throws NoSuchAlgorithmException, NoSuchProviderException {
|
public SecureRandom getSecureRandom() throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||||
return SecureRandom.getInstance("DEFAULT","BCFIPS");
|
return SecureRandom.getInstance("DEFAULT","BCFIPS");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JWEAlgorithmProvider getAesKeyWrapAlgorithmProvider() {
|
public <T> T getAlgorithmProvider(Class<T> clazz, String algorithm) {
|
||||||
return new FIPSAesKeyWrapAlgorithmProvider();
|
Object o = providers.get(algorithm).get();
|
||||||
|
if (o == null) {
|
||||||
|
throw new IllegalArgumentException("Not found provider of algorithm: " + algorithm);
|
||||||
|
}
|
||||||
|
return clazz.cast(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
@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 {
|
||||||
|
}
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
@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 {
|
||||||
|
}
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
@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 {
|
||||||
|
}
|
|
@ -1,25 +1,26 @@
|
||||||
package org.keycloak.crypto.fips.test;
|
package org.keycloak.crypto.fips.test;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.common.crypto.CryptoProviderTypes;
|
||||||
import org.keycloak.crypto.fips.FIPSAesKeyWrapAlgorithmProvider;
|
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.jose.jwe.alg.JWEAlgorithmProvider;
|
||||||
|
import org.keycloak.rule.CryptoInitRule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public class FIPS1402UnitTest {
|
public class FIPS1402UnitTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFips() throws Exception {
|
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);
|
Assert.assertEquals(jweAlg.getClass(), FIPSAesKeyWrapAlgorithmProvider.class);
|
||||||
|
|
||||||
SecureRandom scr = CryptoIntegration.getProvider().getSecureRandom();
|
|
||||||
Assert.assertEquals("BCFIPS", scr.getProvider().getName());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,5 +32,6 @@
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>fips1402</module>
|
<module>fips1402</module>
|
||||||
|
<module>default</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
|
@ -58,6 +58,16 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-crypto-default</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>*</groupId>
|
||||||
|
<artifactId>*</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-adapter-core</artifactId>
|
<artifactId>keycloak-adapter-core</artifactId>
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
<module name="org.keycloak.keycloak-adapter-spi"/>
|
<module name="org.keycloak.keycloak-adapter-spi"/>
|
||||||
<module name="org.keycloak.keycloak-common"/>
|
<module name="org.keycloak.keycloak-common"/>
|
||||||
<module name="org.keycloak.keycloak-core"/>
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
<module name="org.keycloak.keycloak-crypto-default" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-authz-client"/>
|
<module name="org.keycloak.keycloak-authz-client"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-crypto-default">
|
||||||
|
<resources>
|
||||||
|
<artifact name="${org.keycloak:keycloak-crypto-default}"/>
|
||||||
|
</resources>
|
||||||
|
<dependencies>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-annotations"/>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-core"/>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-databind"/>
|
||||||
|
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
|
||||||
|
<module name="org.keycloak.keycloak-common" />
|
||||||
|
<module name="org.keycloak.keycloak-core" />
|
||||||
|
<module name="org.bouncycastle" />
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="javax.activation.api"/>
|
||||||
|
<module name="sun.jdk" optional="true" />
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</module>
|
|
@ -140,6 +140,16 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-crypto-default</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>*</groupId>
|
||||||
|
<artifactId>*</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-js-adapter</artifactId>
|
<artifactId>keycloak-js-adapter</artifactId>
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-crypto-default">
|
||||||
|
<resources>
|
||||||
|
<artifact name="${org.keycloak:keycloak-crypto-default}"/>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-core"/>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-annotations"/>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-databind"/>
|
||||||
|
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
|
||||||
|
<module name="org.keycloak.keycloak-common"/>
|
||||||
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
<module name="org.bouncycastle" />
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="javax.activation.api"/>
|
||||||
|
<module name="sun.jdk" optional="true" />
|
||||||
|
</dependencies>
|
||||||
|
</module>
|
|
@ -27,6 +27,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<module name="org.keycloak.keycloak-common" services="import"/>
|
<module name="org.keycloak.keycloak-common" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-core" services="import"/>
|
<module name="org.keycloak.keycloak-core" services="import"/>
|
||||||
|
<module name="org.keycloak.keycloak-crypto-default" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
|
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
|
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
|
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-crypto-default">
|
||||||
|
<resources>
|
||||||
|
<artifact name="${org.keycloak:keycloak-crypto-default}"/>
|
||||||
|
</resources>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-core"/>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-annotations"/>
|
||||||
|
<module name="com.fasterxml.jackson.core.jackson-databind"/>
|
||||||
|
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
|
||||||
|
<module name="org.keycloak.keycloak-common"/>
|
||||||
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
<module name="org.bouncycastle" />
|
||||||
|
<module name="org.jboss.logging"/>
|
||||||
|
<module name="javax.api"/>
|
||||||
|
<module name="javax.activation.api"/>
|
||||||
|
<module name="sun.jdk" optional="true" />
|
||||||
|
</dependencies>
|
||||||
|
</module>
|
|
@ -27,6 +27,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<module name="org.keycloak.keycloak-common" services="import"/>
|
<module name="org.keycloak.keycloak-common" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-core" services="import"/>
|
<module name="org.keycloak.keycloak-core" services="import"/>
|
||||||
|
<module name="org.keycloak.keycloak-crypto-default" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
|
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
|
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
|
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<module name="org.keycloak.keycloak-common"/>
|
<module name="org.keycloak.keycloak-common"/>
|
||||||
<module name="org.keycloak.keycloak-core"/>
|
<module name="org.keycloak.keycloak-core"/>
|
||||||
|
<module name="org.keycloak.keycloak-crypto-default" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-server-spi" services="import"/>
|
<module name="org.keycloak.keycloak-server-spi" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-server-spi-private" services="import"/>
|
<module name="org.keycloak.keycloak-server-spi-private" services="import"/>
|
||||||
<module name="org.keycloak.keycloak-services" services="import"/>
|
<module name="org.keycloak.keycloak-services" services="import"/>
|
||||||
|
|
|
@ -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
|
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`
|
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:
|
Then unzip and check only bouncycastle-fips libraries are inside "lib" directory:
|
||||||
```
|
```
|
||||||
|
|
37
pom.xml
37
pom.xml
|
@ -1057,6 +1057,12 @@
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-config-api</artifactId>
|
<artifactId>keycloak-config-api</artifactId>
|
||||||
|
@ -1600,7 +1606,12 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-fips1402</artifactId>
|
<artifactId>keycloak-crypto-default</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-crypto-fips1402</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -2124,5 +2135,29 @@
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>crypto-default</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>!fips140-2</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<keycloak.crypto.artifactId>keycloak-crypto-default</keycloak.crypto.artifactId>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>fips140-2</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>fips140-2</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<keycloak.crypto.artifactId>keycloak-crypto-fips1402</keycloak.crypto.artifactId>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -141,6 +141,10 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>${keycloak.crypto.artifactId}</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-server-spi</artifactId>
|
<artifactId>keycloak-server-spi</artifactId>
|
||||||
|
@ -593,52 +597,6 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
<profile>
|
|
||||||
<id>crypto-default</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>!fips140-2</name>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bouncycastle</groupId>
|
|
||||||
<artifactId>bcpkix-jdk15on</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>*</groupId>
|
|
||||||
<artifactId>*</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.bouncycastle</groupId>
|
|
||||||
<artifactId>bcprov-jdk15on</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>*</groupId>
|
|
||||||
<artifactId>*</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</profile>
|
|
||||||
|
|
||||||
<profile>
|
|
||||||
<id>fips140-2</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>fips140-2</name>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-fips1402</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -54,6 +54,11 @@
|
||||||
<groupId>org.apache.santuario</groupId>
|
<groupId>org.apache.santuario</groupId>
|
||||||
<artifactId>xmlsec</artifactId>
|
<artifactId>xmlsec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>${keycloak.crypto.artifactId}</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
|
|
@ -19,9 +19,12 @@ package org.keycloak.saml.processing.core.parsers.saml;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
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.Base64;
|
||||||
import org.keycloak.common.util.DerUtils;
|
import org.keycloak.common.util.DerUtils;
|
||||||
import org.keycloak.common.util.StreamUtil;
|
import org.keycloak.common.util.StreamUtil;
|
||||||
|
@ -128,6 +131,11 @@ public class SAMLParserTest {
|
||||||
@Rule
|
@Rule
|
||||||
public ExpectedException thrown = ExpectedException.none();
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void initCrypto() {
|
||||||
|
CryptoIntegration.init(CryptoProvider.class.getClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void initParser() {
|
public void initParser() {
|
||||||
this.parser = SAMLParser.getInstance();
|
this.parser = SAMLParser.getInstance();
|
||||||
|
|
|
@ -20,7 +20,11 @@ import org.bouncycastle.openssl.PEMKeyPair;
|
||||||
import org.bouncycastle.openssl.PEMParser;
|
import org.bouncycastle.openssl.PEMParser;
|
||||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||||
import org.bouncycastle.util.Arrays;
|
import org.bouncycastle.util.Arrays;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
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.Base64;
|
||||||
import org.keycloak.common.util.DerUtils;
|
import org.keycloak.common.util.DerUtils;
|
||||||
import org.keycloak.dom.saml.v2.assertion.NameIDType;
|
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";
|
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
|
@Test
|
||||||
public void testSaml20Signed() throws Exception {
|
public void testSaml20Signed() throws Exception {
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,17 @@
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<type>test-jar</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>${keycloak.crypto.artifactId}</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.freemarker</groupId>
|
<groupId>org.freemarker</groupId>
|
||||||
<artifactId>freemarker</artifactId>
|
<artifactId>freemarker</artifactId>
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.keycloak.services.resources;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.Config;
|
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.common.util.Resteasy;
|
||||||
import org.keycloak.config.ConfigProviderFactory;
|
import org.keycloak.config.ConfigProviderFactory;
|
||||||
import org.keycloak.exportimport.ExportImportManager;
|
import org.keycloak.exportimport.ExportImportManager;
|
||||||
|
@ -90,6 +92,7 @@ public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
logger.debugv("PlatformProvider: {0}", platform.getClass().getName());
|
logger.debugv("PlatformProvider: {0}", platform.getClass().getName());
|
||||||
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
|
logger.debugv("RestEasy provider: {0}", Resteasy.getProvider().getClass().getName());
|
||||||
|
CryptoIntegration.init(KeycloakApplication.class.getClassLoader());
|
||||||
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,17 @@ import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.keycloak.rule.CryptoInitRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.common.util.StreamUtil;
|
import org.keycloak.common.util.StreamUtil;
|
||||||
|
|
||||||
public class CertificatePemIdentityExtractorTest {
|
public class CertificatePemIdentityExtractorTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtractsCertInPemFormat() throws Exception {
|
public void testExtractsCertInPemFormat() throws Exception {
|
||||||
InputStream is = getClass().getResourceAsStream("/certs/UPN-cert.pem");
|
InputStream is = getClass().getResourceAsStream("/certs/UPN-cert.pem");
|
||||||
|
|
|
@ -21,15 +21,20 @@ import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.common.util.StreamUtil;
|
import org.keycloak.common.util.StreamUtil;
|
||||||
|
import org.keycloak.rule.CryptoInitRule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public class SubjectAltNameIdentityExtractorTest {
|
public class SubjectAltNameIdentityExtractorTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testX509SubjectAltName_otherName() throws Exception {
|
public void testX509SubjectAltName_otherName() throws Exception {
|
||||||
UserIdentityExtractor extractor = UserIdentityExtractor.getSubjectAltNameExtractor(0);
|
UserIdentityExtractor extractor = UserIdentityExtractor.getSubjectAltNameExtractor(0);
|
||||||
|
|
|
@ -32,14 +32,19 @@ import javax.ws.rs.core.Response;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.ClassRule;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.util.CertificateUtils;
|
import org.keycloak.common.util.CertificateUtils;
|
||||||
import org.keycloak.common.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
import org.keycloak.protocol.docker.installation.DockerComposeYamlInstallationProvider;
|
import org.keycloak.protocol.docker.installation.DockerComposeYamlInstallationProvider;
|
||||||
|
import org.keycloak.rule.CryptoInitRule;
|
||||||
|
|
||||||
public class DockerComposeYamlInstallationProviderTest {
|
public class DockerComposeYamlInstallationProviderTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||||
|
|
||||||
DockerComposeYamlInstallationProvider installationProvider;
|
DockerComposeYamlInstallationProvider installationProvider;
|
||||||
static Certificate certificate;
|
static Certificate certificate;
|
||||||
|
|
||||||
|
|
|
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class CryptoInitRule extends ExternalResource {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void before() throws Throwable {
|
||||||
|
CryptoIntegration.init(CryptoProvider.class.getClassLoader());
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.ClassRule;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.model.TestTimedOutException;
|
import org.junit.runners.model.TestTimedOutException;
|
||||||
import org.keycloak.admin.client.Keycloak;
|
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.auth.page.login.UpdatePassword;
|
||||||
import org.keycloak.testsuite.client.KeycloakTestingClient;
|
import org.keycloak.testsuite.client.KeycloakTestingClient;
|
||||||
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
|
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
|
||||||
|
import org.keycloak.testsuite.util.CryptoInitRule;
|
||||||
import org.keycloak.testsuite.util.DroneUtils;
|
import org.keycloak.testsuite.util.DroneUtils;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
import org.keycloak.testsuite.util.TestCleanup;
|
import org.keycloak.testsuite.util.TestCleanup;
|
||||||
|
@ -109,6 +111,9 @@ public abstract class AbstractKeycloakTest {
|
||||||
|
|
||||||
protected Logger log = Logger.getLogger(this.getClass());
|
protected Logger log = Logger.getLogger(this.getClass());
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||||
|
|
||||||
@ArquillianResource
|
@ArquillianResource
|
||||||
protected SuiteContext suiteContext;
|
protected SuiteContext suiteContext;
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,10 @@
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-server-spi-private</artifactId>
|
<artifactId>keycloak-server-spi-private</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>${keycloak.crypto.artifactId}</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-ldap-federation</artifactId>
|
<artifactId>keycloak-ldap-federation</artifactId>
|
||||||
|
|
|
@ -29,8 +29,7 @@ import org.aesh.command.invocation.CommandInvocation;
|
||||||
import org.aesh.command.impl.registry.AeshCommandRegistryBuilder;
|
import org.aesh.command.impl.registry.AeshCommandRegistryBuilder;
|
||||||
import org.aesh.command.registry.CommandRegistry;
|
import org.aesh.command.registry.CommandRegistry;
|
||||||
import org.aesh.command.registry.CommandRegistryException;
|
import org.aesh.command.registry.CommandRegistryException;
|
||||||
import org.keycloak.common.util.Base64;
|
import org.keycloak.common.crypto.CryptoIntegration;
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.credential.hash.PasswordHashProvider;
|
import org.keycloak.credential.hash.PasswordHashProvider;
|
||||||
import org.keycloak.credential.hash.PasswordHashProviderFactory;
|
import org.keycloak.credential.hash.PasswordHashProviderFactory;
|
||||||
import org.keycloak.models.PasswordPolicy;
|
import org.keycloak.models.PasswordPolicy;
|
||||||
|
@ -108,6 +107,8 @@ public class AddUser {
|
||||||
|
|
||||||
File addUserFile = getAddUserFile(this);
|
File addUserFile = getAddUserFile(this);
|
||||||
|
|
||||||
|
CryptoIntegration.init(AddUser.class.getClassLoader());
|
||||||
|
|
||||||
createUser(addUserFile, realm, user, password, roles, iterations);
|
createUser(addUserFile, realm, user, password, roles, iterations);
|
||||||
}
|
}
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
|
|
Loading…
Reference in a new issue