mirror of
https://github.com/keycloak/keycloak.git
synced 2025-12-16 20:15:46 -06:00
Add FIPS suite to the new tests (#43431)
* Add FIPS test suite to the new tests Signed-off-by: Lukas Hanusovsky <lhanusov@redhat.com> * Tweaks to FIPS suite in new test Signed-off-by: stianst <stianst@gmail.com> --------- Signed-off-by: Lukas Hanusovsky <lhanusov@redhat.com> Signed-off-by: stianst <stianst@gmail.com> Co-authored-by: stianst <stianst@gmail.com>
This commit is contained in:
5
.github/scripts/run-fips-it.sh
vendored
5
.github/scripts/run-fips-it.sh
vendored
@@ -8,8 +8,10 @@ if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
STRICT_OPTIONS=""
|
||||
TESTSUITE_NAME="FipsNonStrictTestSuite"
|
||||
if [ "$1" = "strict" ]; then
|
||||
STRICT_OPTIONS="-Dauth.server.fips.mode=strict -Dauth.server.supported.keystore.types=BCFKS -Dauth.server.keystore.type=bcfks -Dauth.server.supported.rsa.key.sizes=2048,3072,4096"
|
||||
TESTSUITE_NAME="FipsStrictTestSuite"
|
||||
fi
|
||||
echo "STRICT_OPTIONS: $STRICT_OPTIONS"
|
||||
TESTS=`testsuite/integration-arquillian/tests/base/testsuites/suite.sh fips`
|
||||
@@ -37,3 +39,6 @@ fi
|
||||
|
||||
# Profile app-server-wildfly needs to be explicitly set for FIPS tests
|
||||
./mvnw test -Dsurefire.rerunFailingTestsCount=$SUREFIRE_RERUN_FAILING_COUNT -nsu -B -Pauth-server-quarkus,auth-server-fips140-2,app-server-wildfly -Dcom.redhat.fips=false $STRICT_OPTIONS -Dtest=$TESTS -pl testsuite/integration-arquillian/tests/base 2>&1 | misc/log/trimmer.sh
|
||||
|
||||
# New Base Tests
|
||||
./mvnw package -nsu -B -Dcom.redhat.fips=false -Dtest=$TESTSUITE_NAME -pl tests/base
|
||||
|
||||
@@ -55,6 +55,7 @@ import io.quarkus.bootstrap.workspace.WorkspaceModuleId;
|
||||
import io.quarkus.maven.dependency.Dependency;
|
||||
import io.quarkus.maven.dependency.DependencyBuilder;
|
||||
import io.quarkus.runtime.configuration.QuarkusConfigFactory;
|
||||
import org.keycloak.quarkus.runtime.configuration.IgnoredArtifacts;
|
||||
|
||||
public class Keycloak {
|
||||
|
||||
@@ -123,7 +124,7 @@ public class Keycloak {
|
||||
addOptionIfNotSet(args, HttpOptions.HTTP_PORT);
|
||||
addOptionIfNotSet(args, HttpOptions.HTTPS_PORT);
|
||||
|
||||
boolean isFipsEnabled = ofNullable(getOptionValue(args, SecurityOptions.FIPS_MODE)).map(FipsMode::valueOf).orElse(FipsMode.DISABLED).isFipsEnabled();
|
||||
boolean isFipsEnabled = ofNullable(getOptionValue(args, SecurityOptions.FIPS_MODE)).map(FipsMode::valueOfOption).orElse(FipsMode.DISABLED).isFipsEnabled();
|
||||
|
||||
if (isFipsEnabled) {
|
||||
String logLevel = getOptionValue(args, LoggingOptions.LOG_LEVEL);
|
||||
@@ -241,11 +242,9 @@ public class Keycloak {
|
||||
.addExclusion("org.jboss.logmanager", "log4j-jboss-logmanager");
|
||||
|
||||
if (fipsEnabled) {
|
||||
serverDependency.addExclusion("org.bouncycastle", "bcprov-jdk18on");
|
||||
serverDependency.addExclusion("org.bouncycastle", "bcpkix-jdk18on");
|
||||
serverDependency.addExclusion("org.keycloak", "keycloak-crypto-default");
|
||||
IgnoredArtifacts.FIPS_ENABLED.stream().map(s -> s.split(":")).forEach(d -> serverDependency.addExclusion(d[0], d[1]));
|
||||
} else {
|
||||
serverDependency.addExclusion("org.keycloak", "keycloak-crypto-fips1402");
|
||||
IgnoredArtifacts.FIPS_DISABLED.stream().map(s -> s.split(":")).forEach(d -> serverDependency.addExclusion(d[0], d[1]));
|
||||
}
|
||||
|
||||
WorkspaceModule.Mutable builder = WorkspaceModule.builder()
|
||||
@@ -256,12 +255,6 @@ public class Keycloak {
|
||||
Dependency.pomImport("org.keycloak", "keycloak-quarkus-parent", keycloakVersion))
|
||||
.addDependency(serverDependency.build());
|
||||
|
||||
if (fipsEnabled) {
|
||||
builder.addDependency(Dependency.of("org.bouncycastle", "bc-fips"));
|
||||
builder.addDependency(Dependency.of("org.bouncycastle", "bctls-fips"));
|
||||
builder.addDependency(Dependency.of("org.bouncycastle", "bcpkix-fips"));
|
||||
}
|
||||
|
||||
for (Dependency dependency : dependencies) {
|
||||
builder.addDependency(dependency);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.keycloak.testframework;
|
||||
import org.keycloak.testframework.admin.AdminClientFactorySupplier;
|
||||
import org.keycloak.testframework.admin.AdminClientSupplier;
|
||||
import org.keycloak.testframework.http.SimpleHttpSupplier;
|
||||
import org.keycloak.testframework.https.ManagedCertificates;
|
||||
import org.keycloak.testframework.infinispan.InfinispanExternalServerSupplier;
|
||||
import org.keycloak.testframework.database.DevFileDatabaseSupplier;
|
||||
import org.keycloak.testframework.database.DevMemDatabaseSupplier;
|
||||
@@ -57,7 +58,8 @@ public class CoreTestFrameworkExtension implements TestFrameworkExtension {
|
||||
public Map<Class<?>, String> valueTypeAliases() {
|
||||
return Map.of(
|
||||
KeycloakServer.class, "server",
|
||||
TestDatabase.class, "database"
|
||||
TestDatabase.class, "database",
|
||||
ManagedCertificates.class, "certificates"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.keycloak.testframework.https;
|
||||
|
||||
public interface CertificatesConfig {
|
||||
|
||||
CertificatesConfigBuilder configure(CertificatesConfigBuilder config);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.keycloak.testframework.https;
|
||||
|
||||
import org.keycloak.common.util.KeystoreUtil;
|
||||
|
||||
public class CertificatesConfigBuilder {
|
||||
|
||||
private KeystoreUtil.KeystoreFormat keystoreFormat = KeystoreUtil.KeystoreFormat.JKS;
|
||||
|
||||
public CertificatesConfigBuilder() {
|
||||
}
|
||||
|
||||
public CertificatesConfigBuilder keystoreFormat(KeystoreUtil.KeystoreFormat keystoreFormat) {
|
||||
this.keystoreFormat = keystoreFormat;
|
||||
return this;
|
||||
}
|
||||
|
||||
public KeystoreUtil.KeystoreFormat getKeystoreFormat() {
|
||||
return this.keystoreFormat;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,27 @@
|
||||
package org.keycloak.testframework.https;
|
||||
|
||||
import org.keycloak.testframework.config.Config;
|
||||
import org.keycloak.testframework.injection.InstanceContext;
|
||||
import org.keycloak.testframework.injection.LifeCycle;
|
||||
import org.keycloak.testframework.injection.RequestedInstance;
|
||||
import org.keycloak.testframework.injection.Supplier;
|
||||
import org.keycloak.testframework.injection.SupplierHelpers;
|
||||
import org.keycloak.testframework.injection.SupplierOrder;
|
||||
|
||||
public class CertificatesSupplier implements Supplier<ManagedCertificates, InjectCertificates> {
|
||||
|
||||
@Override
|
||||
public ManagedCertificates getValue(InstanceContext<ManagedCertificates, InjectCertificates> instanceContext) {
|
||||
return new ManagedCertificates();
|
||||
CertificatesConfig certConfig = SupplierHelpers.getInstance(instanceContext.getAnnotation().config());
|
||||
CertificatesConfigBuilder certBuilder = new CertificatesConfigBuilder();
|
||||
certBuilder = certConfig.configure(certBuilder);
|
||||
|
||||
String supplierConfig = Config.getSupplierConfig(ManagedCertificates.class);
|
||||
if (supplierConfig != null) {
|
||||
CertificatesConfig certConfigOverride = SupplierHelpers.getInstance(supplierConfig);
|
||||
certConfigOverride.configure(certBuilder);
|
||||
}
|
||||
return new ManagedCertificates(certBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.keycloak.testframework.https;
|
||||
|
||||
public class DefaultCertificatesConfig implements CertificatesConfig {
|
||||
|
||||
@Override
|
||||
public CertificatesConfigBuilder configure(CertificatesConfigBuilder config) {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,6 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface InjectCertificates {
|
||||
|
||||
Class<? extends CertificatesConfig> config() default DefaultCertificatesConfig.class;
|
||||
}
|
||||
|
||||
@@ -30,31 +30,35 @@ public class ManagedCertificates {
|
||||
|
||||
private KeyStore serverKeyStore;
|
||||
private KeyStore clientsTrustStore;
|
||||
private final Path serverKeystorePath;
|
||||
private final Path clientsTruststorePath;
|
||||
private final char[] password;
|
||||
|
||||
private final static Path KEYSTORES_DIR = Path.of(System.getProperty("java.io.tmpdir"));
|
||||
private final static Path SERVER_KEYSTORE_FILE_PATH = KEYSTORES_DIR.resolve("kc-testing-server-keystore.jks");
|
||||
private final static Path CLIENTS_TRUSTSTORE_FILE_PATH = KEYSTORES_DIR.resolve("kc-testing-clients-truststore.jks");
|
||||
|
||||
private final static char[] PASSWORD = "password".toCharArray();
|
||||
|
||||
private final static String PRV_KEY_ENTRY = "prvKey";
|
||||
public final static String CERT_ENTRY = "cert";
|
||||
|
||||
|
||||
public ManagedCertificates() throws ManagedCertificatesException {
|
||||
public ManagedCertificates(CertificatesConfigBuilder configBuilder) throws ManagedCertificatesException {
|
||||
if (!CryptoIntegration.isInitialised()) {
|
||||
CryptoIntegration.setProvider(new DefaultCryptoProvider());
|
||||
}
|
||||
cryptoProvider = CryptoIntegration.getProvider();
|
||||
initServerCerts();
|
||||
|
||||
serverKeystorePath = KEYSTORES_DIR.resolve("kc-testing-server-keystore" + "." + configBuilder.getKeystoreFormat().getPrimaryExtension());
|
||||
clientsTruststorePath = KEYSTORES_DIR.resolve("kc-testing-clients-truststore" + "." + configBuilder.getKeystoreFormat().getPrimaryExtension());
|
||||
|
||||
password = configBuilder.getKeystoreFormat() == KeystoreUtil.KeystoreFormat.JKS ? "password".toCharArray() : "passwordpassword".toCharArray();
|
||||
|
||||
initServerCerts(configBuilder.getKeystoreFormat());
|
||||
}
|
||||
|
||||
public String getKeycloakServerKeyStorePath() {
|
||||
return SERVER_KEYSTORE_FILE_PATH.toString();
|
||||
return serverKeystorePath.toString();
|
||||
}
|
||||
|
||||
public String getKeycloakServerKeyStorePassword() {
|
||||
return String.valueOf(PASSWORD);
|
||||
return String.valueOf(password);
|
||||
}
|
||||
|
||||
public KeyStore getClientTrustStore() {
|
||||
@@ -79,26 +83,26 @@ public class ManagedCertificates {
|
||||
}
|
||||
}
|
||||
|
||||
private void initServerCerts() throws ManagedCertificatesException {
|
||||
private void initServerCerts(KeystoreUtil.KeystoreFormat keystoreFormat) throws ManagedCertificatesException {
|
||||
try {
|
||||
serverKeyStore = cryptoProvider.getKeyStore(KeystoreUtil.KeystoreFormat.JKS);
|
||||
clientsTrustStore = cryptoProvider.getKeyStore(KeystoreUtil.KeystoreFormat.JKS);
|
||||
serverKeyStore = cryptoProvider.getKeyStore(keystoreFormat);
|
||||
clientsTrustStore = cryptoProvider.getKeyStore(keystoreFormat);
|
||||
|
||||
if (Files.exists(SERVER_KEYSTORE_FILE_PATH) && Files.exists(CLIENTS_TRUSTSTORE_FILE_PATH)) {
|
||||
if (Files.exists(serverKeystorePath) && Files.exists(clientsTruststorePath)) {
|
||||
LOGGER.debugv("Existing Server KeyStore files found in {0}", KEYSTORES_DIR);
|
||||
|
||||
loadKeyStore(serverKeyStore, SERVER_KEYSTORE_FILE_PATH, PASSWORD);
|
||||
loadKeyStore(clientsTrustStore, CLIENTS_TRUSTSTORE_FILE_PATH, PASSWORD);
|
||||
loadKeyStore(serverKeyStore, serverKeystorePath, password);
|
||||
loadKeyStore(clientsTrustStore, clientsTruststorePath, password);
|
||||
} else {
|
||||
LOGGER.debugv("Generating Server KeyStore files in {0}", KEYSTORES_DIR);
|
||||
|
||||
generateKeystore(serverKeyStore, clientsTrustStore, "localhost");
|
||||
generateKeystoreAndTruststore(serverKeyStore, clientsTrustStore, "localhost");
|
||||
// store the generated keystore and truststore in a temp folder
|
||||
try (FileOutputStream fos = new FileOutputStream(SERVER_KEYSTORE_FILE_PATH.toFile())) {
|
||||
serverKeyStore.store(fos, PASSWORD);
|
||||
try (FileOutputStream fos = new FileOutputStream(serverKeystorePath.toFile())) {
|
||||
serverKeyStore.store(fos, password);
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream(CLIENTS_TRUSTSTORE_FILE_PATH.toFile())) {
|
||||
clientsTrustStore.store(fos, PASSWORD);
|
||||
try (FileOutputStream fos = new FileOutputStream(clientsTruststorePath.toFile())) {
|
||||
clientsTrustStore.store(fos, password);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -112,7 +116,7 @@ public class ManagedCertificates {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateKeystore(KeyStore keyStore, KeyStore trustStore, String subject) throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException, IOException, KeyStoreException, Exception {
|
||||
private void generateKeystoreAndTruststore(KeyStore keyStore, KeyStore trustStore, String subject) throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException, IOException, KeyStoreException, Exception {
|
||||
keyStore.load(null);
|
||||
trustStore.load(null);
|
||||
|
||||
@@ -121,7 +125,7 @@ public class ManagedCertificates {
|
||||
|
||||
keyStore.setCertificateEntry(CERT_ENTRY, cert);
|
||||
trustStore.setCertificateEntry(CERT_ENTRY, cert);
|
||||
keyStore.setKeyEntry(PRV_KEY_ENTRY, keyPair.getPrivate(), PASSWORD, new X509Certificate[]{cert});
|
||||
keyStore.setKeyEntry(PRV_KEY_ENTRY, keyPair.getPrivate(), password, new X509Certificate[]{cert});
|
||||
}
|
||||
|
||||
private KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||
@@ -129,10 +133,10 @@ public class ManagedCertificates {
|
||||
}
|
||||
|
||||
private X509Certificate generateX509CertificateCertificate(KeyPair keyPair, String subject) throws Exception {
|
||||
// generate a v1 certificate
|
||||
// generate a v1 root certificate authority certificate
|
||||
X509Certificate caCert = cryptoProvider.getCertificateUtils().generateV1SelfSignedCertificate(keyPair, subject);
|
||||
|
||||
// generate a v3 certificate
|
||||
// generate a v3 certificate chain
|
||||
return cryptoProvider.getCertificateUtils().generateV3Certificate(keyPair, keyPair.getPrivate(), caCert, subject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ public class SuiteSupport {
|
||||
private static SuiteConfig suiteConfig = new SuiteConfig();
|
||||
|
||||
public static SuiteConfig startSuite() {
|
||||
if (suiteConfig == null) {
|
||||
suiteConfig = new SuiteConfig();
|
||||
}
|
||||
return suiteConfig;
|
||||
}
|
||||
|
||||
@@ -22,7 +25,12 @@ public class SuiteSupport {
|
||||
public static class SuiteConfig {
|
||||
|
||||
public SuiteConfig registerServerConfig(Class<? extends KeycloakServerConfig> serverConfig) {
|
||||
SuiteConfigSource.set("kc.test.server.config", serverConfig.getName());
|
||||
registerSupplierConfig("server", serverConfig);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuiteConfig registerSupplierConfig(String supplierValueType, Class<?> supplierConfig) {
|
||||
SuiteConfigSource.set("kc.test." + supplierValueType + ".config", supplierConfig.getName());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,8 +115,7 @@ public class KeycloakServerConfigBuilder {
|
||||
public boolean tlsEnabled() {
|
||||
return tlsEnabled ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public KeycloakServerConfigBuilder cacheConfigFile(String resourcePath) {
|
||||
try {
|
||||
Path p = Paths.get(Objects.requireNonNull(getClass().getResource(resourcePath)).toURI());
|
||||
|
||||
26
tests/FIPS_104-2.md
Normal file
26
tests/FIPS_104-2.md
Normal file
@@ -0,0 +1,26 @@
|
||||
## FIPS 140-2 testing
|
||||
|
||||
### Integration tests
|
||||
|
||||
On a FIPS enabled platform with FIPS enabled OpenJDK 21, you can run this to test against a Keycloak server with FIPS 140-2 integration enabled.
|
||||
|
||||
```
|
||||
./mvnw clean package -nsu -B -f tests/base/pom.xml \
|
||||
-Dcom.redhat.fips=false \
|
||||
-Dtest=FipsStrictTestSuite,FipsNonStrictTestSuite
|
||||
```
|
||||
FIPS test suite configuration (strict and non-strict):
|
||||
[FipsStrictTestSuite](./base/src/test/java/org/keycloak/tests/suites/FipsStrictTestSuite.java),
|
||||
[FipsNonStrictTestSuite](./base/src/test/java/org/keycloak/tests/suites/FipsNonStrictTestSuite.java)
|
||||
|
||||
NOTE 1: The property `com.redhat.fips` is required for disabling FIPS in JVM, on a FIPS enabled environment (operating system or container), where the test suite is executed.
|
||||
|
||||
NOTE 3: Example of the server startup log, running in an environment (both -> JVM and operating system/container), where FIPS is enabled:
|
||||
```
|
||||
2022-10-11 19:34:29,521 DEBUG [org.keycloak.common.crypto.CryptoIntegration] (main) Using the crypto provider: org.keycloak.crypto.fips.FIPS1402Provider
|
||||
2022-10-11 19:34:31,072 TRACE [org.keycloak.common.crypto.CryptoIntegration] (main) Java security providers: [
|
||||
KC(BCFIPS version 1.000203, FIPS-JVM: enabled) version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider,
|
||||
BCFIPS version 1.000203 - class org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider,
|
||||
BCJSSE version 1.001202 - class org.bouncycastle.jsse.provider.BouncyCastleJsseProvider,
|
||||
]
|
||||
```
|
||||
@@ -15,9 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin;
|
||||
package org.keycloak.tests.admin;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.common.Version;
|
||||
import org.keycloak.crypto.Algorithm;
|
||||
import org.keycloak.keys.Attributes;
|
||||
@@ -25,24 +27,26 @@ import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
|
||||
import org.keycloak.keys.KeyProvider;
|
||||
import org.keycloak.representations.idm.ComponentTypeRepresentation;
|
||||
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.info.ProviderRepresentation;
|
||||
import org.keycloak.representations.info.ServerInfoRepresentation;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.util.KeyUtils;
|
||||
import org.keycloak.testsuite.util.KeystoreUtils;
|
||||
import org.keycloak.testframework.annotations.InjectAdminClient;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.tests.utils.Assert;
|
||||
import org.keycloak.tests.utils.FipsUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ServerInfoTest extends AbstractKeycloakTest {
|
||||
@KeycloakIntegrationTest
|
||||
public class ServerInfoTest {
|
||||
|
||||
@InjectAdminClient
|
||||
Keycloak adminClient;
|
||||
|
||||
@Test
|
||||
public void testServerInfo() {
|
||||
@@ -56,18 +60,21 @@ public class ServerInfoTest extends AbstractKeycloakTest {
|
||||
|
||||
assertNotNull(info.getThemes());
|
||||
assertNotNull(info.getThemes().get("account"));
|
||||
Assert.assertNames(info.getThemes().get("account"), "base", "keycloak.v3", "custom-account-provider");
|
||||
Assert.assertNames(info.getThemes().get("account"), "base", "keycloak.v3");
|
||||
Assert.assertNames(info.getThemes().get("admin"), "base", "keycloak.v2");
|
||||
Assert.assertNames(info.getThemes().get("email"), "base", "keycloak");
|
||||
Assert.assertNames(info.getThemes().get("login"), "address", "base", "environment-agnostic", "keycloak", "keycloak.v2", "organization", "themeconfig");
|
||||
Assert.assertNames(info.getThemes().get("login"), "base", "keycloak", "keycloak.v2");
|
||||
Assert.assertNames(info.getThemes().get("welcome"), "keycloak");
|
||||
|
||||
assertNotNull(info.getEnums());
|
||||
|
||||
assertNotNull(info.getMemoryInfo());
|
||||
assertNotNull(info.getSystemInfo());
|
||||
|
||||
FipsUtils fipsUtils = FipsUtils.create(info);
|
||||
|
||||
assertNotNull(info.getCryptoInfo());
|
||||
Assert.assertNames(info.getCryptoInfo().getSupportedKeystoreTypes(), KeystoreUtils.getSupportedKeystoreTypes());
|
||||
Assert.assertNames(info.getCryptoInfo().getSupportedKeystoreTypes(), fipsUtils.getExpectedSupportedKeyStoreTypes());
|
||||
Assert.assertNames(info.getCryptoInfo().getClientSignatureSymmetricAlgorithms(), Algorithm.HS256, Algorithm.HS384, Algorithm.HS512);
|
||||
Assert.assertNames(info.getCryptoInfo().getClientSignatureAsymmetricAlgorithms(),
|
||||
Algorithm.ES256, Algorithm.ES384, Algorithm.ES512,
|
||||
@@ -83,7 +90,7 @@ public class ServerInfoTest extends AbstractKeycloakTest {
|
||||
.stream()
|
||||
.filter(configProp -> Attributes.KEY_SIZE_KEY.equals(configProp.getName()))
|
||||
.findFirst().orElseThrow(() -> new RuntimeException("Not found provider with ID 'rsa-generated'"));
|
||||
Assert.assertNames(keySizeRep.getOptions(), KeyUtils.getExpectedSupportedRsaKeySizes());
|
||||
Assert.assertNames(keySizeRep.getOptions(), fipsUtils.getExpectedSupportedRsaKeySizes());
|
||||
|
||||
assertEquals(Version.VERSION, info.getSystemInfo().getVersion());
|
||||
assertNotNull(info.getSystemInfo().getServerTime());
|
||||
@@ -91,10 +98,6 @@ public class ServerInfoTest extends AbstractKeycloakTest {
|
||||
|
||||
Map<String, ProviderRepresentation> jpaProviders = info.getProviders().get("connectionsJpa").getProviders();
|
||||
ProviderRepresentation jpaProvider = jpaProviders.values().iterator().next();
|
||||
log.infof("JPA Connections provider info: %s", jpaProvider.getOperationalInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
Assertions.assertNotNull(jpaProvider.getOperationalInfo());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.tests.admin.client;
|
||||
|
||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
|
||||
import org.keycloak.common.crypto.CryptoIntegration;
|
||||
import org.keycloak.common.util.KeystoreUtil;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.crypto.def.DefaultCryptoProvider;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.KeyStoreConfig;
|
||||
import org.keycloak.representations.idm.CertificateRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.testframework.annotations.InjectAdminClient;
|
||||
import org.keycloak.testframework.annotations.InjectAdminEvents;
|
||||
import org.keycloak.testframework.annotations.InjectClient;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.AdminEventAssertion;
|
||||
import org.keycloak.testframework.events.AdminEvents;
|
||||
import org.keycloak.testframework.realm.ManagedClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.tests.utils.admin.AdminEventPaths;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.keycloak.tests.utils.admin.GenerateKeystoreForTestUtil;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
|
||||
*/
|
||||
@KeycloakIntegrationTest
|
||||
public class CredentialsTest {
|
||||
|
||||
@InjectRealm
|
||||
ManagedRealm managedRealm;
|
||||
|
||||
@InjectAdminClient
|
||||
Keycloak adminClient;
|
||||
|
||||
@InjectClient(attachTo = "account")
|
||||
ManagedClient managedClient;
|
||||
|
||||
@InjectAdminEvents
|
||||
AdminEvents adminEvents;
|
||||
|
||||
@BeforeAll
|
||||
public static void init() {
|
||||
if(!CryptoIntegration.isInitialised()) {
|
||||
CryptoIntegration.setProvider(new DefaultCryptoProvider());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAndRegenerateSecret() {
|
||||
CredentialRepresentation oldCredential = managedClient.admin().getSecret();
|
||||
CredentialRepresentation newCredential = managedClient.admin().generateNewSecret();
|
||||
|
||||
CredentialRepresentation secretRep = new CredentialRepresentation();
|
||||
secretRep.setType(CredentialRepresentation.SECRET);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.ACTION, AdminEventPaths.clientGenerateSecretPath(managedClient.getId()), secretRep, ResourceType.CLIENT);
|
||||
|
||||
assertNotNull(oldCredential);
|
||||
assertNotNull(newCredential);
|
||||
assertNotEquals(newCredential.getValue(), oldCredential.getValue());
|
||||
assertEquals(newCredential.getValue(), managedClient.admin().getSecret().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAndRegenerateRegistrationAccessToken() {
|
||||
ClientRepresentation rep = managedClient.admin().toRepresentation();
|
||||
String oldToken = rep.getRegistrationAccessToken();
|
||||
String newToken = managedClient.admin().regenerateRegistrationAccessToken().getRegistrationAccessToken();
|
||||
assertNull(oldToken); // registration access token not saved in ClientRep
|
||||
assertNotNull(newToken); // it's only available via regenerateRegistrationAccessToken()
|
||||
assertNull(managedClient.admin().toRepresentation().getRegistrationAccessToken());
|
||||
|
||||
// Test event
|
||||
ClientRepresentation testedRep = new ClientRepresentation();
|
||||
testedRep.setClientId(rep.getClientId());
|
||||
testedRep.setRegistrationAccessToken(newToken);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.ACTION, AdminEventPaths.clientRegenerateRegistrationAccessTokenPath(managedClient.getId()), testedRep, ResourceType.CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCertificateResource() {
|
||||
ClientAttributeCertificateResource certRsc = managedClient.admin().getCertficateResource("jwt.credential");
|
||||
CertificateRepresentation cert = certRsc.generate();
|
||||
CertificateRepresentation certFromGet = certRsc.getKeyInfo();
|
||||
assertEquals(cert.getCertificate(), certFromGet.getCertificate());
|
||||
assertEquals(cert.getPrivateKey(), certFromGet.getPrivateKey());
|
||||
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.ACTION, AdminEventPaths.clientCertificateGenerateSecretPath(managedClient.getId(), "jwt.credential"), cert, ResourceType.CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadKeyAndCertificate() throws Exception {
|
||||
String certificate2 = "MIICnTCCAYUCBgFPPQDGxTANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdjbGllbnQxMB4XDTE1MDgxNzE4NTAwNVoXDTI1MDgxNzE4NTE0NVowEjEQMA4GA1UEAwwHY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMw3PaBffWxgS2PYSDDBp6As+cNvv9kt2C4f/RDAGmvSIHPFev9kuQiKs3Oaws3ZsV4JG3qHEuYgnh9W4vfe3DwNwtD1bjL5FYBhPBFTw0lAQECYxaBHnkjHwUKp957FqdSPPICm3LjmTcEdlH+9dpp9xHCMbbiNiWDzWI1xSxC8Fs2d0hwz1sd+Q4QeTBPIBWcPM+ICZtNG5MN+ORfayu4X+Me5d0tXG2fQO//rAevk1i5IFjKZuOjTwyKB5SJIY4b8QTeg0g/50IU7Ht00Pxw6CK02dHS+FvXHasZlD3ckomqCDjStTBWdhJo5dST0CbOqalkkpLlCCbGA1yEQRsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAUIMeJ+EAo8eNpCG/nXImacjrKakbFnZYBGD/gqeTGaZynkX+jgBSructTHR83zSH+yELEhsAy+3BfK4EEihp+PEcRnK2fASVkHste8AQ7rlzC+HGGirlwrVhWCdizNUCGK80DE537IZ7nmZw6LFG9P5/Q2MvCsOCYjRUvMkukq6TdXBXR9tETwZ+0gpSfsOxjj0ZF7ftTRUSzx4rFfcbM9fRNdVizdOuKGc8HJPA5lLOxV6CyaYIvi3y5RlQI1OHeS34lE4w9CNPRFa/vdxXvN7ClyzA0HMFNWxBN7pC/Ht/FbhSvaAagJBHg+vCrcY5C26Oli7lAglf/zZrwUPs0w==";
|
||||
|
||||
ClientAttributeCertificateResource certRsc = managedClient.admin().getCertficateResource("jwt.credential");
|
||||
|
||||
KeystoreUtil.KeystoreFormat preferredKeystoreType = KeystoreUtil.KeystoreFormat.valueOf(adminClient.serverInfo().getInfo().getCryptoInfo().getSupportedKeystoreTypes().get(0));
|
||||
|
||||
// Generate keystore file and upload privateKey and certificate from it as JKS store (or eventually PKCS12 or BCFKS store according to which one is preferred type)
|
||||
GenerateKeystoreForTestUtil.KeystoreInfo generatedKeystore = GenerateKeystoreForTestUtil.generateKeystore(preferredKeystoreType, "clientkey", "storepass", "keypass");
|
||||
MultipartFormDataOutput keyCertForm = new MultipartFormDataOutput();
|
||||
|
||||
keyCertForm.addFormData("keystoreFormat", preferredKeystoreType.toString(), MediaType.TEXT_PLAIN_TYPE);
|
||||
keyCertForm.addFormData("keyAlias", "clientkey", MediaType.TEXT_PLAIN_TYPE);
|
||||
keyCertForm.addFormData("keyPassword", "keypass", MediaType.TEXT_PLAIN_TYPE);
|
||||
keyCertForm.addFormData("storePassword", "storepass", MediaType.TEXT_PLAIN_TYPE);
|
||||
|
||||
FileInputStream fs = new FileInputStream(generatedKeystore.getKeystoreFile());
|
||||
byte [] content = fs.readAllBytes();
|
||||
fs.close();
|
||||
keyCertForm.addFormData("file", content, MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
CertificateRepresentation cert = certRsc.uploadJks(keyCertForm);
|
||||
|
||||
// Returned cert is not the new state but rather what was extracted from inputs
|
||||
assertNotNull(cert, "cert not null");
|
||||
assertEquals(generatedKeystore.getCertificateInfo().getCertificate(), cert.getCertificate(), "cert properly extracted");
|
||||
assertEquals(generatedKeystore.getCertificateInfo().getPrivateKey(), cert.getPrivateKey(), "privateKey properly extracted");
|
||||
|
||||
// Get the certificate - to make sure cert was properly updated
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals(generatedKeystore.getCertificateInfo().getCertificate(), cert.getCertificate(), "cert properly set");
|
||||
assertEquals(generatedKeystore.getCertificateInfo().getPrivateKey(), cert.getPrivateKey(), "privateKey properly set");
|
||||
|
||||
// Upload a different certificate via /upload-certificate, privateKey should be nullified
|
||||
MultipartFormDataOutput form = new MultipartFormDataOutput();
|
||||
form.addFormData("keystoreFormat", "Certificate PEM", MediaType.TEXT_PLAIN_TYPE);
|
||||
form.addFormData("file", certificate2.getBytes(StandardCharsets.US_ASCII), MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
cert = certRsc.uploadJksCertificate(form);
|
||||
assertNotNull(cert, "cert not null");
|
||||
assertEquals(certificate2, cert.getCertificate(), "cert properly extracted");
|
||||
assertNull(cert.getPrivateKey(), "privateKey not included");
|
||||
|
||||
// Get the certificate - to make sure cert was properly updated, and privateKey is null
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals(certificate2, cert.getCertificate(), "cert properly set");
|
||||
assertNull(cert.getPrivateKey(), "privateKey nullified");
|
||||
|
||||
// Re-upload the private key
|
||||
certRsc.uploadJks(keyCertForm);
|
||||
|
||||
// Upload certificate as PEM via /upload - nullifies the private key
|
||||
form = new MultipartFormDataOutput();
|
||||
form.addFormData("keystoreFormat", "Certificate PEM", MediaType.TEXT_PLAIN_TYPE);
|
||||
form.addFormData("file", certificate2.getBytes(StandardCharsets.US_ASCII), MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
cert = certRsc.uploadJks(form);
|
||||
assertNotNull(cert, "cert not null");
|
||||
assertEquals(certificate2, cert.getCertificate(), "cert properly extracted");
|
||||
assertNull(cert.getPrivateKey(), "privateKey not included");
|
||||
|
||||
// Get the certificate again - to make sure cert is set, and privateKey is null
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals(certificate2, cert.getCertificate(), "cert properly set");
|
||||
assertNull(cert.getPrivateKey(), "privateKey nullified");
|
||||
|
||||
// Upload certificate with header - should be stored without header
|
||||
form = new MultipartFormDataOutput();
|
||||
form.addFormData("keystoreFormat", "Certificate PEM", MediaType.TEXT_PLAIN_TYPE);
|
||||
|
||||
String certificate2WithHeaders = PemUtils.BEGIN_CERT + "\n" + certificate2 + "\n" + PemUtils.END_CERT;
|
||||
|
||||
form.addFormData("file", certificate2WithHeaders.getBytes(StandardCharsets.US_ASCII), MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
cert = certRsc.uploadJks(form);
|
||||
assertNotNull(cert, "cert not null");
|
||||
assertEquals(certificate2, cert.getCertificate(),"cert properly extracted");
|
||||
assertNull(cert.getPrivateKey(), "privateKey not included");
|
||||
|
||||
// Get the certificate again - to make sure cert is set, and privateKey is null
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals(certificate2, cert.getCertificate(), "cert properly set");
|
||||
assertNull(cert.getPrivateKey(), "privateKey nullified");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloadKeystore() throws Exception {
|
||||
ClientAttributeCertificateResource certRsc = managedClient.admin().getCertficateResource("jwt.credential");
|
||||
|
||||
// generate a key pair first
|
||||
CertificateRepresentation certrep = certRsc.generate();
|
||||
|
||||
KeystoreUtil.KeystoreFormat preferredKeystoreType = KeystoreUtil.KeystoreFormat.valueOf(adminClient.serverInfo().getInfo().getCryptoInfo().getSupportedKeystoreTypes().get(0));
|
||||
|
||||
// download the key and certificate
|
||||
KeyStoreConfig config = new KeyStoreConfig();
|
||||
config.setFormat(preferredKeystoreType.toString());
|
||||
config.setKeyAlias("alias");
|
||||
config.setKeyPassword("keyPass");
|
||||
config.setStorePassword("storePass");
|
||||
byte[] result = certRsc.getKeystore(config);
|
||||
|
||||
KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(preferredKeystoreType);
|
||||
keyStore.load(new ByteArrayInputStream(result), "storePass".toCharArray());
|
||||
Key key = keyStore.getKey("alias", "keyPass".toCharArray());
|
||||
Certificate cert = keyStore.getCertificate("alias");
|
||||
|
||||
assertInstanceOf(X509Certificate.class, cert, "Certificat is X509");
|
||||
String keyPem = KeycloakModelUtils.getPemFromKey(key);
|
||||
String certPem = KeycloakModelUtils.getPemFromCertificate((X509Certificate) cert);
|
||||
|
||||
assertEquals(certrep.getPrivateKey(), keyPem, "key match");
|
||||
assertEquals(certrep.getCertificate(), certPem, "cert match");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateAndDownloadKeystore() throws Exception {
|
||||
ClientAttributeCertificateResource certRsc = managedClient.admin().getCertficateResource("jwt.credential");
|
||||
|
||||
// generate a key pair first
|
||||
CertificateRepresentation firstcert = certRsc.generate();
|
||||
|
||||
KeystoreUtil.KeystoreFormat preferredKeystoreType = KeystoreUtil.KeystoreFormat.valueOf(adminClient.serverInfo().getInfo().getCryptoInfo().getSupportedKeystoreTypes().get(0));
|
||||
|
||||
KeyStoreConfig config = new KeyStoreConfig();
|
||||
config.setFormat(preferredKeystoreType.toString());
|
||||
config.setKeyAlias("alias");
|
||||
config.setKeyPassword("keyPass");
|
||||
config.setStorePassword("storePass");
|
||||
config.setKeySize(4096);
|
||||
config.setValidity(3);
|
||||
byte[] result = certRsc.generateAndGetKeystore(config);
|
||||
KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(preferredKeystoreType);
|
||||
keyStore.load(new ByteArrayInputStream(result), "storePass".toCharArray());
|
||||
Key key = keyStore.getKey("alias", "keyPass".toCharArray());
|
||||
Certificate cert = keyStore.getCertificate("alias");
|
||||
|
||||
assertInstanceOf(X509Certificate.class, cert, "Certificat is X509");
|
||||
String keyPem = KeycloakModelUtils.getPemFromKey(key);
|
||||
String certPem = KeycloakModelUtils.getPemFromCertificate((X509Certificate) cert);
|
||||
|
||||
assertNotEquals(firstcert.getPrivateKey(), keyPem, "new key generated");
|
||||
assertNotEquals(firstcert.getCertificate(), certPem, "new cert generated");
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package org.keycloak.tests.admin.realm;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.bouncycastle.util.Strings;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
@@ -126,9 +125,9 @@ public class RealmDefaultConfigTest extends AbstractRealmTest {
|
||||
role = managedRealm.admin().roles().get("test").toRepresentation();
|
||||
assertNotNull(role);
|
||||
|
||||
managedRealm.admin().roles().get(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + Strings.toLowerCase(managedRealm.getName())).addComposites(Collections.singletonList(role));
|
||||
managedRealm.admin().roles().get(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + managedRealm.getName().toLowerCase()).addComposites(Collections.singletonList(role));
|
||||
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + Strings.toLowerCase(managedRealm.getName())), Collections.singletonList(role), ResourceType.REALM_ROLE);
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath(Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + managedRealm.getName().toLowerCase()), Collections.singletonList(role), ResourceType.REALM_ROLE);
|
||||
|
||||
managedRealm.admin().roles().deleteRole("test");
|
||||
AdminEventAssertion.assertEvent(adminEvents.poll(), OperationType.DELETE, AdminEventPaths.roleResourcePath("test"), ResourceType.REALM_ROLE);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.keycloak.tests.suites;
|
||||
|
||||
import org.junit.platform.suite.api.AfterSuite;
|
||||
import org.junit.platform.suite.api.BeforeSuite;
|
||||
import org.junit.platform.suite.api.SelectClasses;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.KeystoreUtil;
|
||||
import org.keycloak.testframework.https.CertificatesConfig;
|
||||
import org.keycloak.testframework.https.CertificatesConfigBuilder;
|
||||
import org.keycloak.testframework.injection.SuiteSupport;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfig;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfigBuilder;
|
||||
import org.keycloak.tests.admin.ServerInfoTest;
|
||||
import org.keycloak.tests.admin.client.CredentialsTest;
|
||||
|
||||
@Suite
|
||||
@SelectClasses({CredentialsTest.class, ServerInfoTest.class})
|
||||
public class FipsNonStrictTestSuite {
|
||||
|
||||
@BeforeSuite
|
||||
public static void beforeSuite() {
|
||||
SuiteSupport.startSuite()
|
||||
.registerServerConfig(FipsNonStrictServerConfig.class)
|
||||
.registerSupplierConfig("certificates", FipsNonStrictCertificatesConfig.class);;
|
||||
}
|
||||
|
||||
@AfterSuite
|
||||
public static void afterSuite() {
|
||||
SuiteSupport.stopSuite();
|
||||
}
|
||||
|
||||
public static class FipsNonStrictServerConfig implements KeycloakServerConfig {
|
||||
|
||||
@Override
|
||||
public KeycloakServerConfigBuilder configure(KeycloakServerConfigBuilder config) {
|
||||
return config.features(Profile.Feature.FIPS).tlsEnabled(true)
|
||||
.option("fips-mode", "non-strict")
|
||||
.dependency("org.bouncycastle", "bc-fips")
|
||||
.dependency("org.bouncycastle", "bctls-fips")
|
||||
.dependency("org.bouncycastle", "bcpkix-fips")
|
||||
.dependency("org.bouncycastle", "bcutil-fips");
|
||||
}
|
||||
}
|
||||
|
||||
public static class FipsNonStrictCertificatesConfig implements CertificatesConfig {
|
||||
|
||||
@Override
|
||||
public CertificatesConfigBuilder configure(CertificatesConfigBuilder config) {
|
||||
return config.keystoreFormat(KeystoreUtil.KeystoreFormat.PKCS12);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.keycloak.tests.suites;
|
||||
|
||||
import org.junit.platform.suite.api.AfterSuite;
|
||||
import org.junit.platform.suite.api.BeforeSuite;
|
||||
import org.junit.platform.suite.api.SelectClasses;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.KeystoreUtil;
|
||||
import org.keycloak.testframework.https.CertificatesConfig;
|
||||
import org.keycloak.testframework.https.CertificatesConfigBuilder;
|
||||
import org.keycloak.testframework.injection.SuiteSupport;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfig;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfigBuilder;
|
||||
import org.keycloak.tests.admin.ServerInfoTest;
|
||||
import org.keycloak.tests.admin.client.CredentialsTest;
|
||||
|
||||
@Suite
|
||||
@SelectClasses({CredentialsTest.class, ServerInfoTest.class})
|
||||
public class FipsStrictTestSuite {
|
||||
|
||||
@BeforeSuite
|
||||
public static void beforeSuite() {
|
||||
SuiteSupport.startSuite()
|
||||
.registerServerConfig(FipsStrictServerConfig.class)
|
||||
.registerSupplierConfig("certificates", FipsStrictCertificatesConfig.class);
|
||||
}
|
||||
|
||||
@AfterSuite
|
||||
public static void afterSuite() {
|
||||
SuiteSupport.stopSuite();
|
||||
}
|
||||
|
||||
public static class FipsStrictServerConfig implements KeycloakServerConfig {
|
||||
|
||||
@Override
|
||||
public KeycloakServerConfigBuilder configure(KeycloakServerConfigBuilder config) {
|
||||
return config.features(Profile.Feature.FIPS).tlsEnabled(true)
|
||||
.option("fips-mode", "strict")
|
||||
.option("spi-password-hashing-pbkdf2-max-padding-length", "14")
|
||||
.option("spi-password-hashing-pbkdf2-sha256-max-padding-length", "14")
|
||||
.option("spi-password-hashing-pbkdf2-sha512-max-padding-length", "14")
|
||||
.dependency("org.bouncycastle", "bc-fips")
|
||||
.dependency("org.bouncycastle", "bctls-fips")
|
||||
.dependency("org.bouncycastle", "bcpkix-fips")
|
||||
.dependency("org.bouncycastle", "bcutil-fips");
|
||||
}
|
||||
}
|
||||
|
||||
public static class FipsStrictCertificatesConfig implements CertificatesConfig {
|
||||
|
||||
@Override
|
||||
public CertificatesConfigBuilder configure(CertificatesConfigBuilder config) {
|
||||
return config.keystoreFormat(KeystoreUtil.KeystoreFormat.BCFKS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,9 @@ package org.keycloak.tests.suites;
|
||||
|
||||
import org.junit.platform.suite.api.SelectClasses;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
import org.keycloak.tests.admin.AdminHeadersTest;
|
||||
import org.keycloak.tests.admin.client.CredentialsTest;
|
||||
|
||||
@Suite
|
||||
// TODO: Select relevant test classes or packages once they have been migrated
|
||||
@SelectClasses(AdminHeadersTest.class)
|
||||
@SelectClasses({CredentialsTest.class})
|
||||
public class JDKTestSuite {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.keycloak.tests.utils;
|
||||
|
||||
import org.keycloak.representations.info.ServerInfoRepresentation;
|
||||
|
||||
public class FipsUtils {
|
||||
|
||||
private final String cryptoProvider;
|
||||
|
||||
private FipsUtils(ServerInfoRepresentation info) {
|
||||
this.cryptoProvider = info.getCryptoInfo().getCryptoProvider();
|
||||
}
|
||||
|
||||
public static FipsUtils create(ServerInfoRepresentation info) {
|
||||
return new FipsUtils(info);
|
||||
}
|
||||
|
||||
public String[] getExpectedSupportedKeyStoreTypes() {
|
||||
return switch (cryptoProvider) {
|
||||
case "FIPS1402Provider" -> new String[] { "PKCS12", "BCFKS" };
|
||||
case "Fips1402StrictCryptoProvider" -> new String[] { "BCFKS" };
|
||||
default -> new String[] { "JKS", "PKCS12", "BCFKS" };
|
||||
};
|
||||
}
|
||||
|
||||
public String[] getExpectedSupportedRsaKeySizes() {
|
||||
return switch (cryptoProvider) {
|
||||
case "Fips1402StrictCryptoProvider" -> new String[]{"2048", "3072", "4096"};
|
||||
default -> new String[]{"1024", "2048", "3072", "4096"};
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.keycloak.tests.utils.admin;
|
||||
|
||||
import org.keycloak.common.crypto.CryptoIntegration;
|
||||
import org.keycloak.common.util.CertificateUtils;
|
||||
import org.keycloak.common.util.KeyUtils;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.representations.idm.CertificateRepresentation;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public class GenerateKeystoreForTestUtil {
|
||||
|
||||
private final static Path KEYSTORES_DIR = Path.of(System.getProperty("java.io.tmpdir"));
|
||||
|
||||
public static KeystoreInfo generateKeystore(org.keycloak.common.util.KeystoreUtil.KeystoreFormat keystoreType, String subject, String keystorePassword, String keyPassword) throws Exception {
|
||||
return generateKeystore(keystoreType, subject, keystorePassword, keyPassword, KeyUtils.generateRsaKeyPair(2048));
|
||||
}
|
||||
|
||||
public static KeystoreInfo generateKeystore(org.keycloak.common.util.KeystoreUtil.KeystoreFormat keystoreType, String subject, String keystorePassword, String keyPassword, KeyPair keyPair) throws Exception {
|
||||
X509Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, subject);
|
||||
return generateKeystore(keystoreType, subject, keystorePassword, keyPassword, keyPair.getPrivate(), certificate);
|
||||
}
|
||||
|
||||
public static KeystoreInfo generateKeystore(org.keycloak.common.util.KeystoreUtil.KeystoreFormat keystoreType,
|
||||
String subject, String keystorePassword, String keyPassword, PrivateKey privKey, Certificate certificate) throws Exception {
|
||||
String fileName = "keystore." + keystoreType.getPrimaryExtension();
|
||||
|
||||
KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(keystoreType);
|
||||
keyStore.load(null, null);
|
||||
Certificate[] chain = {certificate};
|
||||
keyStore.setKeyEntry(subject, privKey, keyPassword.trim().toCharArray(), chain);
|
||||
|
||||
File file = KEYSTORES_DIR.resolve(fileName).toFile();
|
||||
keyStore.store(new FileOutputStream(file), keystorePassword.trim().toCharArray());
|
||||
|
||||
CertificateRepresentation certRep = new CertificateRepresentation();
|
||||
certRep.setPrivateKey(PemUtils.encodeKey(privKey));
|
||||
certRep.setPublicKey(PemUtils.encodeKey(certificate.getPublicKey()));
|
||||
certRep.setCertificate(PemUtils.encodeCertificate(certificate));
|
||||
return new KeystoreInfo(certRep, file);
|
||||
}
|
||||
|
||||
public static class KeystoreInfo {
|
||||
private final CertificateRepresentation certificateInfo;
|
||||
private final File keystoreFile;
|
||||
|
||||
private KeystoreInfo(CertificateRepresentation certificateInfo, File keystoreFile) {
|
||||
this.certificateInfo = certificateInfo;
|
||||
this.keystoreFile = keystoreFile;
|
||||
}
|
||||
|
||||
public CertificateRepresentation getCertificateInfo() {
|
||||
return certificateInfo;
|
||||
}
|
||||
|
||||
public File getKeystoreFile() {
|
||||
return keystoreFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
|
||||
* as indicated by the @author tags. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.admin.client;
|
||||
|
||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.common.crypto.CryptoIntegration;
|
||||
import org.keycloak.common.util.KeystoreUtil;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.KeyStoreConfig;
|
||||
import org.keycloak.representations.idm.CertificateRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.testsuite.AbstractClientTest;
|
||||
import org.keycloak.testsuite.util.AdminEventPaths;
|
||||
import org.keycloak.testsuite.util.KeystoreUtils;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
|
||||
*/
|
||||
public class CredentialsTest extends AbstractClientTest {
|
||||
|
||||
private ClientResource accountClient;
|
||||
private String accountClientDbId;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
accountClient = findClientResourceById("account");
|
||||
accountClientDbId = accountClient.toRepresentation().getId();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAndRegenerateSecret() {
|
||||
CredentialRepresentation oldCredential = accountClient.getSecret();
|
||||
CredentialRepresentation newCredential = accountClient.generateNewSecret();
|
||||
|
||||
CredentialRepresentation secretRep = new CredentialRepresentation();
|
||||
secretRep.setType(CredentialRepresentation.SECRET);
|
||||
assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientGenerateSecretPath(accountClientDbId), secretRep, ResourceType.CLIENT);
|
||||
|
||||
assertNotNull(oldCredential);
|
||||
assertNotNull(newCredential);
|
||||
assertNotEquals(newCredential.getValue(), oldCredential.getValue());
|
||||
assertEquals(newCredential.getValue(), accountClient.getSecret().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAndRegenerateRegistrationAccessToken() {
|
||||
ClientRepresentation rep = accountClient.toRepresentation();
|
||||
String oldToken = rep.getRegistrationAccessToken();
|
||||
String newToken = accountClient.regenerateRegistrationAccessToken().getRegistrationAccessToken();
|
||||
assertNull(oldToken); // registration access token not saved in ClientRep
|
||||
assertNotNull(newToken); // it's only available via regenerateRegistrationAccessToken()
|
||||
assertNull(accountClient.toRepresentation().getRegistrationAccessToken());
|
||||
|
||||
// Test event
|
||||
ClientRepresentation testedRep = new ClientRepresentation();
|
||||
testedRep.setClientId(rep.getClientId());
|
||||
testedRep.setRegistrationAccessToken(newToken);
|
||||
assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientRegenerateRegistrationAccessTokenPath(accountClientDbId), testedRep, ResourceType.CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCertificateResource() {
|
||||
ClientAttributeCertificateResource certRsc = accountClient.getCertficateResource("jwt.credential");
|
||||
CertificateRepresentation cert = certRsc.generate();
|
||||
CertificateRepresentation certFromGet = certRsc.getKeyInfo();
|
||||
assertEquals(cert.getCertificate(), certFromGet.getCertificate());
|
||||
assertEquals(cert.getPrivateKey(), certFromGet.getPrivateKey());
|
||||
|
||||
assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientCertificateGenerateSecretPath(accountClientDbId, "jwt.credential"), cert, ResourceType.CLIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadKeyAndCertificate() throws Exception {
|
||||
TemporaryFolder folder = new TemporaryFolder();
|
||||
folder.create();
|
||||
try {
|
||||
String certificate2 = "MIICnTCCAYUCBgFPPQDGxTANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdjbGllbnQxMB4XDTE1MDgxNzE4NTAwNVoXDTI1MDgxNzE4NTE0NVowEjEQMA4GA1UEAwwHY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMw3PaBffWxgS2PYSDDBp6As+cNvv9kt2C4f/RDAGmvSIHPFev9kuQiKs3Oaws3ZsV4JG3qHEuYgnh9W4vfe3DwNwtD1bjL5FYBhPBFTw0lAQECYxaBHnkjHwUKp957FqdSPPICm3LjmTcEdlH+9dpp9xHCMbbiNiWDzWI1xSxC8Fs2d0hwz1sd+Q4QeTBPIBWcPM+ICZtNG5MN+ORfayu4X+Me5d0tXG2fQO//rAevk1i5IFjKZuOjTwyKB5SJIY4b8QTeg0g/50IU7Ht00Pxw6CK02dHS+FvXHasZlD3ckomqCDjStTBWdhJo5dST0CbOqalkkpLlCCbGA1yEQRsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAUIMeJ+EAo8eNpCG/nXImacjrKakbFnZYBGD/gqeTGaZynkX+jgBSructTHR83zSH+yELEhsAy+3BfK4EEihp+PEcRnK2fASVkHste8AQ7rlzC+HGGirlwrVhWCdizNUCGK80DE537IZ7nmZw6LFG9P5/Q2MvCsOCYjRUvMkukq6TdXBXR9tETwZ+0gpSfsOxjj0ZF7ftTRUSzx4rFfcbM9fRNdVizdOuKGc8HJPA5lLOxV6CyaYIvi3y5RlQI1OHeS34lE4w9CNPRFa/vdxXvN7ClyzA0HMFNWxBN7pC/Ht/FbhSvaAagJBHg+vCrcY5C26Oli7lAglf/zZrwUPs0w==";
|
||||
|
||||
ClientAttributeCertificateResource certRsc = accountClient.getCertficateResource("jwt.credential");
|
||||
|
||||
KeystoreUtil.KeystoreFormat preferredKeystoreType = KeystoreUtils.getPreferredKeystoreType();
|
||||
|
||||
// Generate keystore file and upload privateKey and certificate from it as JKS store (or eventually PKCS12 or BCFKS store according to which one is preferred type)
|
||||
KeystoreUtils.KeystoreInfo generatedKeystore = KeystoreUtils.generateKeystore(folder, preferredKeystoreType, "clientkey", "storepass", "keypass");
|
||||
MultipartFormDataOutput keyCertForm = new MultipartFormDataOutput();
|
||||
|
||||
keyCertForm.addFormData("keystoreFormat", preferredKeystoreType.toString(), MediaType.TEXT_PLAIN_TYPE);
|
||||
keyCertForm.addFormData("keyAlias", "clientkey", MediaType.TEXT_PLAIN_TYPE);
|
||||
keyCertForm.addFormData("keyPassword", "keypass", MediaType.TEXT_PLAIN_TYPE);
|
||||
keyCertForm.addFormData("storePassword", "storepass", MediaType.TEXT_PLAIN_TYPE);
|
||||
|
||||
FileInputStream fs = new FileInputStream(generatedKeystore.getKeystoreFile());
|
||||
byte [] content = fs.readAllBytes();
|
||||
fs.close();
|
||||
keyCertForm.addFormData("file", content, MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
CertificateRepresentation cert = certRsc.uploadJks(keyCertForm);
|
||||
|
||||
// Returned cert is not the new state but rather what was extracted from inputs
|
||||
assertNotNull("cert not null", cert);
|
||||
assertEquals("cert properly extracted", generatedKeystore.getCertificateInfo().getCertificate(), cert.getCertificate());
|
||||
assertEquals("privateKey properly extracted", generatedKeystore.getCertificateInfo().getPrivateKey(), cert.getPrivateKey());
|
||||
|
||||
// Get the certificate - to make sure cert was properly updated
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals("cert properly set", generatedKeystore.getCertificateInfo().getCertificate(), cert.getCertificate());
|
||||
assertEquals("privateKey properly set", generatedKeystore.getCertificateInfo().getPrivateKey(), cert.getPrivateKey());
|
||||
|
||||
// Upload a different certificate via /upload-certificate, privateKey should be nullified
|
||||
MultipartFormDataOutput form = new MultipartFormDataOutput();
|
||||
form.addFormData("keystoreFormat", "Certificate PEM", MediaType.TEXT_PLAIN_TYPE);
|
||||
form.addFormData("file", certificate2.getBytes(Charset.forName("ASCII")), MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
cert = certRsc.uploadJksCertificate(form);
|
||||
assertNotNull("cert not null", cert);
|
||||
assertEquals("cert properly extracted", certificate2, cert.getCertificate());
|
||||
assertNull("privateKey not included", cert.getPrivateKey());
|
||||
|
||||
// Get the certificate - to make sure cert was properly updated, and privateKey is null
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals("cert properly set", certificate2, cert.getCertificate());
|
||||
assertNull("privateKey nullified", cert.getPrivateKey());
|
||||
|
||||
// Re-upload the private key
|
||||
certRsc.uploadJks(keyCertForm);
|
||||
|
||||
// Upload certificate as PEM via /upload - nullifies the private key
|
||||
form = new MultipartFormDataOutput();
|
||||
form.addFormData("keystoreFormat", "Certificate PEM", MediaType.TEXT_PLAIN_TYPE);
|
||||
form.addFormData("file", certificate2.getBytes(Charset.forName("ASCII")), MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
cert = certRsc.uploadJks(form);
|
||||
assertNotNull("cert not null", cert);
|
||||
assertEquals("cert properly extracted", certificate2, cert.getCertificate());
|
||||
assertNull("privateKey not included", cert.getPrivateKey());
|
||||
|
||||
// Get the certificate again - to make sure cert is set, and privateKey is null
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals("cert properly set", certificate2, cert.getCertificate());
|
||||
assertNull("privateKey nullified", cert.getPrivateKey());
|
||||
|
||||
// Upload certificate with header - should be stored without header
|
||||
form = new MultipartFormDataOutput();
|
||||
form.addFormData("keystoreFormat", "Certificate PEM", MediaType.TEXT_PLAIN_TYPE);
|
||||
|
||||
String certificate2WithHeaders = PemUtils.BEGIN_CERT + "\n" + certificate2 + "\n" + PemUtils.END_CERT;
|
||||
|
||||
form.addFormData("file", certificate2WithHeaders.getBytes(Charset.forName("ASCII")), MediaType.APPLICATION_OCTET_STREAM_TYPE);
|
||||
cert = certRsc.uploadJks(form);
|
||||
assertNotNull("cert not null", cert);
|
||||
assertEquals("cert properly extracted", certificate2, cert.getCertificate());
|
||||
assertNull("privateKey not included", cert.getPrivateKey());
|
||||
|
||||
// Get the certificate again - to make sure cert is set, and privateKey is null
|
||||
cert = certRsc.getKeyInfo();
|
||||
assertEquals("cert properly set", certificate2, cert.getCertificate());
|
||||
assertNull("privateKey nullified", cert.getPrivateKey());
|
||||
} finally {
|
||||
folder.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloadKeystore() throws Exception {
|
||||
ClientAttributeCertificateResource certRsc = accountClient.getCertficateResource("jwt.credential");
|
||||
|
||||
// generate a key pair first
|
||||
CertificateRepresentation certrep = certRsc.generate();
|
||||
|
||||
KeystoreUtil.KeystoreFormat preferredKeystoreType = KeystoreUtils.getPreferredKeystoreType();
|
||||
|
||||
// download the key and certificate
|
||||
KeyStoreConfig config = new KeyStoreConfig();
|
||||
config.setFormat(preferredKeystoreType.toString());
|
||||
config.setKeyAlias("alias");
|
||||
config.setKeyPassword("keyPass");
|
||||
config.setStorePassword("storePass");
|
||||
byte[] result = certRsc.getKeystore(config);
|
||||
|
||||
KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(preferredKeystoreType);
|
||||
keyStore.load(new ByteArrayInputStream(result), "storePass".toCharArray());
|
||||
Key key = keyStore.getKey("alias", "keyPass".toCharArray());
|
||||
Certificate cert = keyStore.getCertificate("alias");
|
||||
|
||||
assertTrue("Certificat is X509", cert instanceof X509Certificate);
|
||||
String keyPem = KeycloakModelUtils.getPemFromKey(key);
|
||||
String certPem = KeycloakModelUtils.getPemFromCertificate((X509Certificate) cert);
|
||||
|
||||
assertEquals("key match", certrep.getPrivateKey(), keyPem);
|
||||
assertEquals("cert match", certrep.getCertificate(), certPem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateAndDownloadKeystore() throws Exception {
|
||||
ClientAttributeCertificateResource certRsc = accountClient.getCertficateResource("jwt.credential");
|
||||
|
||||
// generate a key pair first
|
||||
CertificateRepresentation firstcert = certRsc.generate();
|
||||
|
||||
KeystoreUtil.KeystoreFormat preferredKeystoreType = KeystoreUtils.getPreferredKeystoreType();
|
||||
|
||||
KeyStoreConfig config = new KeyStoreConfig();
|
||||
config.setFormat(preferredKeystoreType.toString());
|
||||
config.setKeyAlias("alias");
|
||||
config.setKeyPassword("keyPass");
|
||||
config.setStorePassword("storePass");
|
||||
config.setKeySize(4096);
|
||||
config.setValidity(3);
|
||||
byte[] result = certRsc.generateAndGetKeystore(config);
|
||||
KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(preferredKeystoreType);
|
||||
keyStore.load(new ByteArrayInputStream(result), "storePass".toCharArray());
|
||||
Key key = keyStore.getKey("alias", "keyPass".toCharArray());
|
||||
Certificate cert = keyStore.getCertificate("alias");
|
||||
|
||||
assertTrue("Certificat is X509", cert instanceof X509Certificate);
|
||||
String keyPem = KeycloakModelUtils.getPemFromKey(key);
|
||||
String certPem = KeycloakModelUtils.getPemFromCertificate((X509Certificate) cert);
|
||||
|
||||
assertNotEquals("new key generated", firstcert.getPrivateKey(), keyPem);
|
||||
assertNotEquals("new cert generated", firstcert.getCertificate(), certPem);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ LoginTotpTest
|
||||
PasswordHashingTest
|
||||
ClientAuthSignedJWTTest
|
||||
ClientAuthEdDSASignedJWTTest
|
||||
CredentialsTest
|
||||
JavaKeystoreKeyProviderTest
|
||||
ServerInfoTest
|
||||
UserFederationLdapConnectionTest
|
||||
LDAPUserLoginTest
|
||||
org.keycloak.testsuite.x509.**
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
AccountRestServiceTest
|
||||
AuthorizationCodeTest
|
||||
CredentialsTest
|
||||
DeployedScriptAuthenticatorTest
|
||||
ExportImportTest
|
||||
GeneratedRsaKeyProviderTest
|
||||
|
||||
Reference in New Issue
Block a user