feature: add option for creating a global truststore (#24473)

closes #24148

Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
Co-authored-by: Martin Bartoš <mabartos@redhat.com>
This commit is contained in:
Steven Hawkins 2023-11-30 02:57:17 -05:00 committed by GitHub
parent dd5b9b1c36
commit 8c3df19722
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
62 changed files with 1030 additions and 287 deletions

View file

@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.keycloak.truststore;
package org.keycloak.common.enums;
public enum HostnameVerificationPolicy {

View file

@ -13,6 +13,9 @@ include::topics/templates/document-attributes.adoc[]
:release_header_latest_link: {releasenotes_link_latest}
include::topics/templates/release-header.adoc[]
== {project_name_full} 24.0.0
include::topics/24_0_0.adoc[leveloffset=2]
== {project_name_full} 23.0.0
include::topics/23_0_0.adoc[leveloffset=2]

View file

@ -2,8 +2,12 @@
The Keycloak JS adapter now uses the https://webpack.js.org/guides/package-exports/[`exports` field] in `package.json`. This improves support for more modern bundlers like Webpack 5 and Vite, but comes with some unavoidable breaking changes. Consult the link:{upgradingguide_link}[{upgradingguide_name}] for more details.
= Truststore Improvements
Keycloak introduces an improved truststores configuration options. The Keycloak truststore is now used across the server: for outgoing connections, mTLS, database drivers and more. It's no longer needed to configure separate truststores for individual areas. To configure the truststore, you can put your truststores files or certificates in the default `conf/truststores`, or use the new `truststore-paths` config option. For details refer to the relevant https://www.keycloak.org/server/keycloak-truststore[guide].
== Automatic certificate management for SAML identity providers
The SAML identity providers can now be configured to automatically download the signing certificates from the IDP entity metadata descriptor endpoint. In order to use the new feature the option `Metadata descriptor URL` should be configured in the provider (URL where the IDP metadata information with the certificates is published) and `Use metadata descriptor URL` needs to be `ON`. The certificates are automatically downloaded and cached in the `public-key-storage` SPI from that URL. The certificates can also be reloaded or imported from the admin console, using the action combo in the provider page.
See the https://www.keycloak.org/docs/latest/server_admin/index.html#saml-v2-0-identity-providers[documentation] for more details about the new options.
See the https://www.keycloak.org/docs/latest/server_admin/index.html#saml-v2-0-identity-providers[documentation] for more details about the new options.

View file

@ -74,11 +74,9 @@ Hover the mouse pointer over the tooltips in the Admin Console to see more detai
==== Connecting to LDAP over SSL
When you configure a secure connection URL to your LDAP store (for example,`ldaps://myhost.com:636`), {project_name} uses SSL to communicate with the LDAP server. Configure a truststore on the {project_name} server side so that {project_name} can trust the SSL connection to LDAP.
When you configure a secure connection URL to your LDAP store (for example,`ldaps://myhost.com:636`), {project_name} uses SSL to communicate with the LDAP server. Configure a truststore on the {project_name} server side so that {project_name} can trust the SSL connection to LDAP - see https://www.keycloak.org/server/keycloak-truststore[Configuring a Truststore] {section}.
Configure the global truststore for {project_name} with the Truststore SPI. For more information about configuring the global truststore, see the https://www.keycloak.org/server/keycloak-truststore[Configuring a Truststore] {section}. If you do not configure the Truststore SPI, the truststore falls back to the default mechanism provided by Java, which can be the file supplied by the `javax.net.ssl.trustStore` system property or the cacerts file from the JDK if the system property is unset.
The `Use Truststore SPI` configuration property, in the LDAP federation provider configuration, controls the truststore SPI. By default, {project_name} sets the property to `Always`, which is adequate for most deployments. {project_name} uses the Truststore SPI if the connection URL to LDAP starts with `ldaps` only.
The `Use Truststore SPI` configuration property is deprecated. It should normally be left as `Always`.
==== Synchronizing LDAP users to {project_name}

View file

@ -12,3 +12,9 @@ import AuthZ from 'keycloak-js/dist/keycloak-authz.js';
import Keycloak from 'keycloak-js';
import AuthZ from 'keycloak-js/authz';
----
= Truststore Changes
The `spi-truststore-file-*` options and the truststore related options `https-trust-store-*` are deprecated, please use the new default location for truststore material, `conf/truststores`, or specify your desired paths via the `truststore-paths` option. For details refer to the relevant https://www.keycloak.org/server/keycloak-truststore[guide].
The `tls-hostname-verifier` property should be used instead of the `spi-truststore-file-hostname-verification-policy` property.

View file

@ -1,5 +1,9 @@
== Migration Changes
=== Migrating to 24.0.0
include::changes-24_0_0.adoc[leveloffset=3]
=== Migrating to 23.0.2
include::changes-23_0_2.adoc[leveloffset=3]

View file

@ -2,52 +2,36 @@
<#import "/templates/kc.adoc" as kc>
<@tmpl.guide
title="Configuring trusted certificates for outgoing requests"
summary="How to configure the {project_name} Truststore to communicate with external services through TLS."
includedOptions="">
title="Configuring trusted certificates"
summary="How to configure the {project_name} Truststore to communicate through TLS."
includedOptions="truststore-paths tls-hostname-verifier">
When {project_name} communicates with external services through TLS, it has to validate the remote servers certificate in order to ensure it is connecting to a trusted server. This is necessary in order to prevent man-in-the-middle attacks. The certificates of these remote servers or the CA that signed these certificates must be put in a truststore. This truststore is managed by the Keycloak server.
When {project_name} communicates with external services or has an incoming connection through TLS, it has to validate the remote certificate in order to ensure it is connecting to a trusted server. This is necessary in order to prevent man-in-the-middle attacks.
The truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. It is also useful
when you want to change the policy on how host names are verified and trusted by the server.
The certificates of these clients or servers, or the CA that signed these certificates, must be put in a truststore. This truststore is then configured for use by Keycloak.
By default, a truststore provider is not configured, and any TLS/HTTPS connections fall back to standard Java Truststore configuration. If there is no trust established, then these outgoing requests will fail.
== Configuring the System Truststore
== Configuring the {project_name} Truststore
The existing Java default truststore certs will always be trusted. If you need additional certificates, which will be the case if you have self-signed or internal certificate authorities that are not recognized by the JRE, they can be included in the `conf/truststores` directory or subdirectories. The certs may be in PEM files, or PKCS12 files with extension `.p12` or `.pfx`. If in PKCS12, the certs must be unencrypted - meaning no password is expected.
You can add your truststore configuration by entering this command:
If you need an alternative path, use the `--truststore-paths` option to specify additional files or directories where PEM or PKCS12 files are located. Paths are relative to where you launched {project_name}, so absolute paths are recommended instead. If a directory is specified, it will be recursively scanned for truststore files.
<@kc.start parameters="--spi-truststore-file-file=myTrustStore.jks --spi-truststore-file-password=password --spi-truststore-file-hostname-verification-policy=ANY"/>
After all applicable certs are included, the truststore will be used as the system default truststore via the `javax.net.ssl` properties, and as the default for internal usage within {project_name}.
The following are possible configuration options for this setting:
For example:
file::
The path to a Java keystore file.
TLS requests need a way to verify the host of the server to which they are talking.
This is what the truststore does.
The keystore contains one or more trusted host certificates or certificate authorities.
This truststore file should only contain public certificates of your secured hosts.
This is _REQUIRED_ if any of these properties are defined.
<@kc.start parameters="--truststore-paths=/opt/truststore/myTrustStore.pfx,/opt/other-truststore/myOtherTrustStore.pem" />
password::
Password of the keystore.
This option is _REQUIRED_ if any of these properties are defined.
It is still possible to directly set your own `javax.net.ssl` truststore System properties, but it's recommended to use the `--truststore-paths` instead.
hostname-verification-policy::
For HTTPS requests, this option verifies the hostname of the server's certificate. Default: `WILDCARD`
== Hostname Verification Policy
You may refine how hostnames are verified by TLS connections with the `tls-hostname-verifier` property.
* `WILDCARD` (the default) allows wildcards in subdomain names, such as *.foo.com.
* `ANY` means that the hostname is not verified.
* `WILDCARD` allows wildcards in subdomain names, such as *.foo.com.
* When using `STRICT`, the Common Name (CN) must match the hostname exactly.
+
Please note that this setting does not apply to LDAP secure connections, which require strict hostname checking.
type::
The type of truststore, such as `jks`, `pkcs12` or `bcfks`. If not provided, the type would be detected based on the truststore
file extension or platform default type.
=== Example of a truststore configuration
The following is an example configuration for a truststore that allows you to create trustful connections to all `mycompany.org` domains and its subdomains:
<@kc.start parameters="--spi-truststore-file-file=path/to/truststore.jks --spi-truststore-file-password=change_me --spi-truststore-file-hostname-verification-policy=WILDCARD"/>
</@tmpl.guide>

View file

@ -89,17 +89,17 @@ public class HttpOptions {
public static final Option HTTPS_TRUST_STORE_FILE = new OptionBuilder<>("https-trust-store-file", File.class)
.category(OptionCategory.HTTP)
.description("The trust store which holds the certificate information of the certificates to trust.")
.description("DEPRECATED: The trust store which holds the certificate information of the certificates to trust.")
.build();
public static final Option HTTPS_TRUST_STORE_PASSWORD = new OptionBuilder<>("https-trust-store-password", String.class)
.category(OptionCategory.HTTP)
.description("The password of the trust store file.")
.description("DEPRECATED: The password of the trust store file.")
.build();
public static final Option<String> HTTPS_TRUST_STORE_TYPE = new OptionBuilder<>("https-trust-store-type", String.class)
.category(OptionCategory.HTTP)
.description("The type of the trust store file. " +
.description("DEPRECATED: The type of the trust store file. " +
"If not given, the type is automatically detected based on the file name. " +
"If '" + SecurityOptions.FIPS_MODE.getKey() + "' is set to '" + FipsMode.STRICT + "' and no value is set, it defaults to 'BCFKS'.")
.build();

View file

@ -7,13 +7,14 @@ public enum OptionCategory {
TRANSACTION("Transaction",30, ConfigSupportLevel.SUPPORTED),
FEATURE("Feature", 40, ConfigSupportLevel.SUPPORTED),
HOSTNAME("Hostname", 50, ConfigSupportLevel.SUPPORTED),
HTTP("HTTP/TLS", 60, ConfigSupportLevel.SUPPORTED),
HTTP("HTTP(S)", 60, ConfigSupportLevel.SUPPORTED),
HEALTH("Health", 70, ConfigSupportLevel.SUPPORTED),
CONFIG("Config", 75, ConfigSupportLevel.SUPPORTED),
METRICS("Metrics", 80, ConfigSupportLevel.SUPPORTED),
PROXY("Proxy", 90, ConfigSupportLevel.SUPPORTED),
VAULT("Vault", 100, ConfigSupportLevel.SUPPORTED),
LOGGING("Logging", 110, ConfigSupportLevel.SUPPORTED),
TRUSTSTORE("Truststore", 115, ConfigSupportLevel.SUPPORTED),
SECURITY("Security", 120, ConfigSupportLevel.SUPPORTED),
EXPORT("Export", 130, ConfigSupportLevel.SUPPORTED),
IMPORT("Import", 140, ConfigSupportLevel.SUPPORTED),

View file

@ -1,11 +1,11 @@
package org.keycloak.config;
import java.util.Arrays;
import java.util.List;
import org.keycloak.common.Profile;
import org.keycloak.common.crypto.FipsMode;
import java.util.Arrays;
import java.util.List;
public class SecurityOptions {
public static final Option<FipsMode> FIPS_MODE = new OptionBuilder<>("fips-mode", FipsMode.class)

View file

@ -0,0 +1,18 @@
package org.keycloak.config;
import org.keycloak.common.enums.HostnameVerificationPolicy;
public class TruststoreOptions {
public static final Option<String> TRUSTSTORE_PATHS = new OptionBuilder<>("truststore-paths", String.class)
.category(OptionCategory.TRUSTSTORE)
.description("List of pkcs12 (p12 or pfx file extensions), PEM files, or directories containing those files that will be used as a system truststore.")
.build();
public static final Option<HostnameVerificationPolicy> HOSTNAME_VERIFICATION_POLICY = new OptionBuilder<>("tls-hostname-verifier", HostnameVerificationPolicy.class)
.category(OptionCategory.TRUSTSTORE)
.description("The TLS hostname verification policy for out-going HTTPS and SMTP requests.")
.defaultValue(HostnameVerificationPolicy.WILDCARD)
.build();
}

View file

@ -230,6 +230,13 @@ class KeycloakProcessor {
recorder.configureProfile(profile.getName(), profile.getFeatures());
}
@Record(ExecutionTime.STATIC_INIT)
@BuildStep
@Consume(ConfigBuildItem.class)
void configureTruststore(KeycloakRecorder recorder) {
recorder.configureTruststore();
}
/**
* Check whether JDBC driver is present for the specified DB
*

View file

@ -80,6 +80,14 @@
<include>*.*</include>
</includes>
</fileSet>
<!-- create an empty truststores directory -->
<fileSet>
<directory>src/main/content/conf</directory>
<outputDirectory>conf/truststores</outputDirectory>
<excludes>
<exclude>**/*</exclude>
</excludes>
</fileSet>
<fileSet>
<directory>src/main/content/data</directory>
<outputDirectory>data</outputDirectory>

View file

@ -1,4 +1,7 @@
Configure the server
====================
Files in this directory are used to configure the server. Please consult the [configuration guides](https://www.keycloak.org/guides#server) for more information.
Files in this directory are used to configure the server. Please consult the [configuration guides](https://www.keycloak.org/guides#server) for more information.
Use the truststores subdirectory to provide additional trusted certificates. Please consult the [truststore guide](https://www.keycloak.org/server/keycloak-truststore) for more information.

View file

@ -17,11 +17,13 @@
package org.keycloak.quarkus.runtime;
import java.io.File;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import io.agroal.api.AgroalDataSource;
import io.quarkus.agroal.DataSource;
@ -32,13 +34,13 @@ import liquibase.Scope;
import org.hibernate.cfg.AvailableSettings;
import org.infinispan.manager.DefaultCacheManager;
import io.vertx.ext.web.RoutingContext;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.crypto.FipsMode;
import org.keycloak.config.TruststoreOptions;
import org.keycloak.quarkus.runtime.configuration.Configuration;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
import org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory;
@ -48,6 +50,7 @@ import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
import org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory;
import org.keycloak.theme.ClasspathThemeProviderFactory;
import org.keycloak.truststore.TruststoreBuilder;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.ShutdownContext;
@ -68,6 +71,23 @@ public class KeycloakRecorder {
Profile.init(profileName, features);
}
public void configureTruststore() {
String[] truststores = Configuration.getOptionalKcValue(TruststoreOptions.TRUSTSTORE_PATHS.getKey())
.map(s -> s.split(",")).orElse(new String[0]);
String dataDir = Environment.getDataDir();
File truststoresDir = Optional.ofNullable(Environment.getHomePath()).map(path -> path.resolve("conf").resolve("truststores").toFile()).orElse(null);
if (truststoresDir != null && truststoresDir.exists() && Optional.ofNullable(truststoresDir.list()).map(a -> a.length).orElse(0) > 0) {
truststores = Stream.concat(Stream.of(truststoresDir.getAbsolutePath()), Stream.of(truststores)).toArray(String[]::new);
} else if (truststores.length == 0) {
return; // nothing to configure, we'll just use the system default
}
TruststoreBuilder.setSystemTruststore(truststores, true, dataDir);
}
public void configureLiquibase(Map<String, List<String>> services) {
ServiceLocator locator = Scope.getCurrentScope().getServiceLocator();
if (locator instanceof FastServiceLocator)

View file

@ -40,6 +40,7 @@ public final class PropertyMappers {
MAPPERS.addAll(SecurityPropertyMappers.getMappers());
MAPPERS.addAll(ExportPropertyMappers.getMappers());
MAPPERS.addAll(ImportPropertyMappers.getMappers());
MAPPERS.addAll(TruststorePropertyMappers.getMappers());
}
public static ConfigValue getValue(ConfigSourceInterceptorContext context, String name) {

View file

@ -21,7 +21,7 @@ final class SecurityPropertyMappers {
return new PropertyMapper[] {
fromOption(SecurityOptions.FIPS_MODE).transformer(SecurityPropertyMappers::resolveFipsMode)
.paramLabel("mode")
.build()
.build(),
};
}

View file

@ -0,0 +1,21 @@
package org.keycloak.quarkus.runtime.configuration.mappers;
import org.keycloak.config.TruststoreOptions;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
public class TruststorePropertyMappers {
public static PropertyMapper[] getMappers() {
return new PropertyMapper[] {
fromOption(TruststoreOptions.TRUSTSTORE_PATHS)
.paramLabel(TruststoreOptions.TRUSTSTORE_PATHS.getKey())
.build(),
fromOption(TruststoreOptions.HOSTNAME_VERIFICATION_POLICY)
.paramLabel(TruststoreOptions.HOSTNAME_VERIFICATION_POLICY.getKey())
.to("kc.spi-truststore-file-hostname-verification-policy")
.build(),
};
}
}

View file

@ -105,6 +105,20 @@ public class FipsDistTest {
});
}
@Test
void testUnencryptedPkcs12TrustStoreInStrictMode(KeycloakDistribution dist) {
runOnFipsEnabledDistribution(dist, () -> {
String truststoreName = "keycloak-truststore.p12";
dist.copyOrReplaceFileFromClasspath("/" + truststoreName, Path.of("conf", truststoreName));
RawKeycloakDistribution rawDist = dist.unwrap(RawKeycloakDistribution.class);
Path truststorePath = rawDist.getDistPath().resolve("conf").resolve(truststoreName).toAbsolutePath();
CLIResult cliResult = dist.run("--verbose", "start", "--fips-mode=strict", "--truststore-paths=" + truststorePath);
cliResult.assertStarted();
});
}
@Test
void testUnsupportedHttpsPkcs12KeyStoreInStrictMode(KeycloakDistribution dist) {
runOnFipsEnabledDistribution(dist, () -> {

View file

@ -0,0 +1,86 @@
/*
* Copyright 2021 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.it.cli.dist;
import io.restassured.RestAssured;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
import org.keycloak.it.utils.KeycloakDistribution;
import org.keycloak.it.utils.RawKeycloakDistribution;
import org.keycloak.truststore.TruststoreBuilder;
import java.nio.file.Path;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static io.restassured.RestAssured.given;
@DistributionTest(keepAlive = true)
@RawDistOnly(reason = "Containers are immutable")
public class TruststoreDistTest {
@BeforeAll
static void before() {
RestAssured.reset();
}
@Test
void testMutualAuthWithTruststorePaths(KeycloakDistribution dist) {
String[] truststoreNames = new String[] { "keycloak-truststore.p12", "self-signed.pem" };
Stream.of(truststoreNames).forEach(truststoreName -> {
dist.copyOrReplaceFileFromClasspath("/" + truststoreName, Path.of("conf", truststoreName));
});
RawKeycloakDistribution rawDist = dist.unwrap(RawKeycloakDistribution.class);
String paths = Stream.of(truststoreNames).map(truststoreName -> rawDist.getDistPath().resolve("conf")
.resolve(truststoreName).toAbsolutePath().toString()).collect(Collectors.joining(","));
dist.copyOrReplaceFileFromClasspath("/self-signed.p12", Path.of("conf", "self-signed.p12"));
Path keyStore = rawDist.getDistPath().resolve("conf").resolve("self-signed.p12").toAbsolutePath();
rawDist.run("--verbose", "start", "--http-enabled=true", "--hostname=mykeycloak.org",
"--truststore-paths=" + paths, "--https-client-auth=required", "--https-key-store-file=" + keyStore);
given().trustStore(TruststoreDistTest.class.getResource("/self-signed-truststore.p12").getPath(), TruststoreBuilder.DUMMY_PASSWORD)
.keyStore(TruststoreDistTest.class.getResource("/self-signed.p12").getPath(), "password")
.get("https://mykeycloak.org:8443").then().body(Matchers.containsString("https://mykeycloak.org"));
}
@Test
void testMutualAuthWithDefaultTruststoresDir(KeycloakDistribution dist) {
String[] truststoreNames = new String[] { "keycloak-truststore.p12", "self-signed.pem" };
Stream.of(truststoreNames).forEach(truststoreName -> {
dist.copyOrReplaceFileFromClasspath("/" + truststoreName, Path.of("conf", "truststores", truststoreName));
});
RawKeycloakDistribution rawDist = dist.unwrap(RawKeycloakDistribution.class);
dist.copyOrReplaceFileFromClasspath("/self-signed.p12", Path.of("conf", "self-signed.p12"));
Path keyStore = rawDist.getDistPath().resolve("conf").resolve("self-signed.p12").toAbsolutePath();
rawDist.run("--verbose", "start", "--http-enabled=true", "--hostname=mykeycloak.org",
"--https-client-auth=required", "--https-key-store-file=" + keyStore);
given().trustStore(TruststoreDistTest.class.getResource("/self-signed-truststore.p12").getPath(), TruststoreBuilder.DUMMY_PASSWORD)
.keyStore(TruststoreDistTest.class.getResource("/self-signed.p12").getPath(), "password")
.get("https://mykeycloak.org:8443").then().body(Matchers.containsString("https://mykeycloak.org"));
}
}

View file

@ -60,7 +60,7 @@ Feature:
multi-site, par, preview, recovery-codes, scripts, step-up-authentication,
token-exchange, transient-users, update-email, web-authn.
HTTP/TLS:
HTTP(S):
--http-relative-path <path>
Set the path relative to '/' for serving resources. The path must start with a

View file

@ -60,7 +60,7 @@ Feature:
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
transient-users, update-email, web-authn.
HTTP/TLS:
HTTP(S):
--http-relative-path <path>
Set the path relative to '/' for serving resources. The path must start with a

View file

@ -130,6 +130,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Export:
--dir <dir> Set the path to a directory where files will be created with the exported data.

View file

@ -130,6 +130,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Export:
--dir <dir> Set the path to a directory where files will be created with the exported data.
@ -142,4 +151,4 @@ Export:
--users-per-file <number>
Set the number of users per file. It is used only if 'users' is set to
'different_files'. Increasing this number leads to exponentially increasing
export times. Default: 50.
export times. Default: 50.

View file

@ -130,6 +130,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Import:
--dir <dir> Set the path to a directory where files will be read from.

View file

@ -130,6 +130,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Import:
--dir <dir> Set the path to a directory where files will be read from.

View file

@ -116,7 +116,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -150,14 +150,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -245,6 +245,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -111,7 +111,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -145,14 +145,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -228,6 +228,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -116,7 +116,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -150,14 +150,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -245,6 +245,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -111,7 +111,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -145,14 +145,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -228,6 +228,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -117,7 +117,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -151,14 +151,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -246,6 +246,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -112,7 +112,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -146,14 +146,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -229,6 +229,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -117,7 +117,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -151,14 +151,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -246,6 +246,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -112,7 +112,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -146,14 +146,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Health:
@ -229,6 +229,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
Security:
--fips-mode <mode> Sets the FIPS mode. If 'non-strict' is set, FIPS is enabled but on

View file

@ -76,7 +76,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -107,14 +107,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Config:
@ -188,6 +188,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
By default, this command tries to update the server configuration by running a
'build' before starting the server. You can disable this behavior by using the
'--optimized' option:

View file

@ -69,7 +69,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -100,14 +100,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Proxy:
@ -169,6 +169,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
By default, this command tries to update the server configuration by running a
'build' before starting the server. You can disable this behavior by using the
'--optimized' option:

View file

@ -76,7 +76,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -107,14 +107,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Config:
@ -188,6 +188,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
By default, this command tries to update the server configuration by running a
'build' before starting the server. You can disable this behavior by using the
'--optimized' option:

View file

@ -69,7 +69,7 @@ Hostname:
URL this option should be enabled. Default: false.
--hostname-url <url> Set the base URL for frontend URLs, including scheme, host, port and path.
HTTP/TLS:
HTTP(S):
--http-enabled <true|false>
Enables the HTTP listener. Default: false.
@ -100,14 +100,14 @@ HTTP/TLS:
--https-protocols <protocols>
The list of protocols to explicitly enable. Default: TLSv1.3,TLSv1.2.
--https-trust-store-file <file>
The trust store which holds the certificate information of the certificates to
trust.
DEPRECATED: The trust store which holds the certificate information of the
certificates to trust.
--https-trust-store-password <password>
The password of the trust store file.
DEPRECATED: The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
DEPRECATED: The type of the trust store file. If not given, the type is
automatically detected based on the file name. If 'fips-mode' is set to
'strict' and no value is set, it defaults to 'BCFKS'.
Proxy:
@ -169,6 +169,15 @@ Logging:
categories and their levels. For the root category, you don't need to
specify a category. Default: info.
Truststore:
--tls-hostname-verifier <tls-hostname-verifier>
The TLS hostname verification policy for out-going HTTPS and SMTP requests.
Possible values are: ANY, WILDCARD, STRICT. Default: WILDCARD.
--truststore-paths <truststore-paths>
List of pkcs12 (p12 or pfx file extensions), PEM files, or directories
containing those files that will be used as a system truststore.
By default, this command tries to update the server configuration by running a
'build' before starting the server. You can disable this behavior by using the
'--optimized' option:

View file

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDezCCAmOgAwIBAgIEM0VH1DANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQGEwJL
QzERMA8GA1UECBMIa2V5Y2xvYWsxETAPBgNVBAcTCGtleWNsb2FrMREwDwYDVQQK
EwhrZXljbG9hazERMA8GA1UECxMIa2V5Y2xvYWsxEjAQBgNVBAMTCUtleSBDbG9h
azAgFw0yMzExMDkxMjMxNDZaGA8yMDUxMDMyNjEyMzE0NlowbTELMAkGA1UEBhMC
S0MxETAPBgNVBAgTCGtleWNsb2FrMREwDwYDVQQHEwhrZXljbG9hazERMA8GA1UE
ChMIa2V5Y2xvYWsxETAPBgNVBAsTCGtleWNsb2FrMRIwEAYDVQQDEwlLZXkgQ2xv
YWswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv1M8ZiKSONnryBcTy
u6u0d/cJ9s0kZAvO+Q62I5W6e6r0zFYlUjheRSTF7PdypAxhJPMRVGZoE0WCKUMn
4D1E43ZC8bl8IgzpC8m2hbtJsVcbZs0H4D9jHjHvBiPgdkmTc7F/pU8jk8oD3L+Y
olzOFLI/wpwC7kx9O1bzXVpTKOg12JqrKRHIfdvU4mbMlRTRX+AX6Iw5QMiy8vfA
77uCkkxPInx18Z4MU6vqjvAWXos5gQE1fVUyHsmWlBp8Eis7jD7d52Th1uK3nJLo
4wnKzNXDXq34o25xR6j1BpU+v8iqkcDdpJncQHuo/iHK2WZh8xgQMxGoc33nslxB
JvuPAgMBAAGjITAfMB0GA1UdDgQWBBTp2UwAeIxtlKqNFrW4jUVnJ8CgAjANBgkq
hkiG9w0BAQsFAAOCAQEANfkQnompu7woA7fCJb5O+WCNTGoAdFO36tjyRczbRO2G
W7GqPFupObQhAQTtZ55pBfhZTz30lrM9C6vAMDIhfqjYfdATeflALCZH4lbLRcxf
bMq/FVRz1p+hEUGwNeguxCiZ7ZqfqchwiW8oeEeG4MYdYOfdR1pglF6Ak0pkWwqE
KqfuTjllGJRkLJco6ApDA6viBnGUX9T4Xb+xsfzTiOj93k9Z1aWzLB4MCupS+Z1h
VC39DBEUe04OEczu8ZT4A20hiOp+wA2YuToxVVncpnMdZhe1hbzKrTTflM22mcs1
6Fqjo2BBJQ/sfhWMB7KYpnI78n/bkVP2S4hE3JChXA==
-----END CERTIFICATE-----

View file

@ -258,11 +258,12 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
URL contextRoot = new URL(scheme + "://localhost:" + port + ("/" + relativePath + "/realms/master/").replace("//", "/"));
HttpURLConnection connection = null;
long startTime = System.currentTimeMillis();
Exception ex = null;
while (true) {
if (System.currentTimeMillis() - startTime > getStartTimeout()) {
throw new IllegalStateException(
"Timeout [" + getStartTimeout() + "] while waiting for Quarkus server");
"Timeout [" + getStartTimeout() + "] while waiting for Quarkus server", ex);
}
if (!keycloak.isAlive()) {
@ -287,6 +288,7 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
break;
}
} catch (Exception ignore) {
ex = ignore;
} finally {
if (connection != null) {
connection.disconnect();
@ -314,12 +316,15 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
private SSLSocketFactory createInsecureSslSocketFactory() throws IOException {
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}

View file

@ -17,6 +17,7 @@
package org.keycloak.truststore;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import org.keycloak.provider.Provider;
import java.security.cert.X509Certificate;

View file

@ -198,11 +198,11 @@ public class DefaultHttpClientFactory implements HttpClientFactory {
TruststoreProvider truststoreProvider = session.getProvider(TruststoreProvider.class);
boolean disableTruststoreProvider = truststoreProvider == null || truststoreProvider.getTruststore() == null;
if (disableTruststoreProvider) {
logger.warn("TruststoreProvider is disabled");
} else {
builder.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.valueOf(truststoreProvider.getPolicy().name()));
builder.hostnameVerification(truststoreProvider.getPolicy());
try {
builder.trustStore(truststoreProvider.getTruststore());
} catch (Exception e) {
@ -214,7 +214,7 @@ public class DefaultHttpClientFactory implements HttpClientFactory {
logger.warn("TrustManager is disabled");
builder.disableTrustManager();
}
if (clientKeystore != null) {
clientKeystore = EnvUtil.replace(clientKeystore);
try {

View file

@ -27,6 +27,7 @@ import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.NoConnectionReuseStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@ -53,35 +54,23 @@ import java.util.concurrent.TimeUnit;
* @version $Revision: 1 $
*/
public class HttpClientBuilder {
public enum HostnameVerificationPolicy {
/**
* Hostname verification is not done on the server's certificate
*/
ANY,
/**
* Allows wildcards in subdomain names i.e. *.foo.com
*/
WILDCARD,
/**
* CN must match hostname connecting to
*/
STRICT
}
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
private static class PassthroughTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}

View file

@ -19,10 +19,10 @@ package org.keycloak.email;
import jakarta.mail.internet.MimeUtility;
import org.jboss.logging.Logger;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserModel;
import org.keycloak.services.ServicesLogger;
import org.keycloak.truststore.HostnameVerificationPolicy;
import org.keycloak.truststore.JSSETruststoreConfigurator;
import org.keycloak.vault.VaultStringSecret;

View file

@ -17,6 +17,8 @@
package org.keycloak.truststore;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.Map;

View file

@ -19,6 +19,7 @@ package org.keycloak.truststore;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
@ -27,7 +28,6 @@ import org.keycloak.provider.ProviderConfigurationBuilder;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
@ -53,6 +53,8 @@ import javax.security.auth.x500.X500Principal;
*/
public class FileTruststoreProviderFactory implements TruststoreProviderFactory {
static final String HOSTNAME_VERIFICATION_POLICY = "hostname-verification-policy";
private static final Logger log = Logger.getLogger(FileTruststoreProviderFactory.class);
private TruststoreProvider provider;
@ -72,29 +74,40 @@ public class FileTruststoreProviderFactory implements TruststoreProviderFactory
String storepath = config.get("file");
String pass = config.get("password");
String policy = config.get("hostname-verification-policy");
String policy = config.get(HOSTNAME_VERIFICATION_POLICY);
String configuredType = config.get("type");
// if "truststore" . "file" is not configured then it is disabled
if (storepath == null && pass == null && policy == null) {
return;
}
HostnameVerificationPolicy verificationPolicy = null;
KeyStore truststore = null;
boolean system = false;
if (storepath == null) {
throw new RuntimeException("Attribute 'file' missing in 'truststore':'file' configuration");
storepath = System.getProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_KEY);
if (storepath == null) {
File defaultTrustStore = TruststoreBuilder.getJRETruststore();
if (!defaultTrustStore.exists()) {
throw new RuntimeException("Attribute 'file' missing in 'truststore':'file' configuration, and could not find the system truststore");
}
storepath = defaultTrustStore.getAbsolutePath();
system = true;
}
// should there be an exception if pass / type are configured for the spi-truststore
pass = System.getProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_PASSWORD_KEY, system ? "changeit" : null);
configuredType = System.getProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_TYPE_KEY);
}
if (pass == null) {
throw new RuntimeException("Attribute 'password' missing in 'truststore':'file' configuration");
}
String type = KeystoreUtil.getKeystoreType(configuredType, storepath, KeyStore.getDefaultType());
try {
truststore = loadStore(storepath, type, pass == null ? null :pass.toCharArray());
} catch (Exception e) {
throw new RuntimeException("Failed to initialize TruststoreProviderFactory: " + new File(storepath).getAbsolutePath() + ", truststore type: " + type, e);
// in fips mode the default truststore type can be pkcs12, but the cacerts file will still be jks
if (system && !"jks".equalsIgnoreCase(type)) {
try {
truststore = loadStore(storepath, "jks", pass == null ? null :pass.toCharArray());
} catch (Exception e1) {
}
}
if (truststore == null) {
throw new RuntimeException("Failed to initialize TruststoreProviderFactory: " + new File(storepath).getAbsolutePath() + ", truststore type: " + type, e);
}
}
if (policy == null) {
verificationPolicy = HostnameVerificationPolicy.WILDCARD;
@ -115,15 +128,9 @@ public class FileTruststoreProviderFactory implements TruststoreProviderFactory
private KeyStore loadStore(String path, String type, char[] password) throws Exception {
KeyStore ks = KeyStore.getInstance(type);
InputStream is = new FileInputStream(path);
try {
try (InputStream is = new FileInputStream(path)) {
ks.load(is, password);
return ks;
} finally {
try {
is.close();
} catch (IOException ignored) {
}
}
}
@ -146,24 +153,24 @@ public class FileTruststoreProviderFactory implements TruststoreProviderFactory
.property()
.name("file")
.type("string")
.helpText("The file path of the trust store from where the certificates are going to be read from to validate TLS connections.")
.helpText("DEPRECATED: The file path of the trust store from where the certificates are going to be read from to validate TLS connections.")
.add()
.property()
.name("password")
.type("string")
.helpText("The trust store password.")
.helpText("DEPRECATED: The trust store password.")
.add()
.property()
.name("hostname-verification-policy")
.name(HOSTNAME_VERIFICATION_POLICY)
.type("string")
.helpText("The hostname verification policy.")
.helpText("DEPRECATED: The hostname verification policy.")
.options(Arrays.stream(HostnameVerificationPolicy.values()).map(HostnameVerificationPolicy::name).map(String::toLowerCase).toArray(String[]::new))
.defaultValue(HostnameVerificationPolicy.WILDCARD.name().toLowerCase())
.add()
.property()
.name("type")
.type("string")
.helpText("Type of the truststore. If not provided, the type would be detected based on the truststore file extension or platform default type.")
.helpText("DEPRECATED: Type of the truststore. If not provided, the type would be detected based on the truststore file extension or platform default type.")
.add()
.build();
}
@ -184,14 +191,14 @@ public class FileTruststoreProviderFactory implements TruststoreProviderFactory
private void readTruststore(KeyStore truststore) {
//Reading truststore aliases & certificates
Enumeration enumeration;
Enumeration<String> enumeration;
try {
enumeration = truststore.aliases();
log.trace("Checking " + truststore.size() + " entries from the truststore.");
while(enumeration.hasMoreElements()) {
String alias = (String)enumeration.nextElement();
String alias = enumeration.nextElement();
readTruststoreEntry(truststore, alias);
}
} catch (KeyStoreException e) {

View file

@ -17,14 +17,10 @@
package org.keycloak.truststore;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@ -94,29 +90,6 @@ public class JSSETruststoreConfigurator {
return tm;
}
public HostnameVerifier getHostnameVerifier() {
if (provider == null) {
return null;
}
HostnameVerificationPolicy policy = provider.getPolicy();
switch (policy) {
case ANY:
return new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
};
case WILDCARD:
return new BrowserCompatHostnameVerifier();
case STRICT:
return new StrictHostnameVerifier();
default:
throw new IllegalStateException("Unknown policy: " + policy.name());
}
}
public TruststoreProvider getProvider() {
return provider;
}

View file

@ -0,0 +1,246 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.truststore;
import org.jboss.logging.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Optional;
import java.util.stream.Stream;
/**
* Builds a system-wide truststore from the given config options.
*/
public class TruststoreBuilder {
public static final String SYSTEM_TRUSTSTORE_KEY = "javax.net.ssl.trustStore";
public static final String SYSTEM_TRUSTSTORE_PASSWORD_KEY = "javax.net.ssl.trustStorePassword";
public static final String SYSTEM_TRUSTSTORE_TYPE_KEY = "javax.net.ssl.trustStoreType";
private static final String CERT_PROTECTION_ALGORITHM_KEY = "keystore.pkcs12.certProtectionAlgorithm";
public static final String DUMMY_PASSWORD = "keycloakchangeit"; // fips length compliant dummy password
static final String PKCS12 = "PKCS12";
private static final Logger LOGGER = Logger.getLogger(TruststoreBuilder.class);
public static void setSystemTruststore(String[] truststores, boolean trustStoreIncludeDefault, String dataDir) {
KeyStore truststore = createMergedTruststore(truststores, trustStoreIncludeDefault);
// save with a dummy password just in case some logic that uses the system properties needs to have one
File file = saveTruststore(truststore, dataDir, DUMMY_PASSWORD.toCharArray());
// finally update the system properties
System.setProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_KEY, file.getAbsolutePath());
System.setProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_TYPE_KEY, PKCS12);
System.setProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_PASSWORD_KEY, DUMMY_PASSWORD);
}
static File saveTruststore(KeyStore truststore, String dataDir, char[] password) {
File file = new File(dataDir, "keycloak-truststore.p12");
file.getParentFile().mkdirs();
try (FileOutputStream fos = new FileOutputStream(file)) {
// this should inhibit the use of encryption in storing the certs
// it's of course not concurrency safe, but it should only be run at startup
String oldValue = System.setProperty(CERT_PROTECTION_ALGORITHM_KEY, "NONE");
truststore.store(fos, password);
if (oldValue != null) {
System.setProperty(CERT_PROTECTION_ALGORITHM_KEY, oldValue);
} else {
System.getProperties().remove(CERT_PROTECTION_ALGORITHM_KEY);
}
} catch (Exception e) {
throw new RuntimeException("Failed to save truststore: " + file.getAbsolutePath(), e);
}
return file;
}
static KeyStore createMergedTruststore(String[] truststores, boolean trustStoreIncludeDefault) {
KeyStore truststore = createPkcs12KeyStore();
if (trustStoreIncludeDefault) {
includeDefaultTruststore(truststore);
}
mergeFiles(truststores, truststore, true);
return truststore;
}
private static void mergeFiles(String[] truststores, KeyStore truststore, boolean topLevel) {
for (String file : truststores) {
File f = new File(file);
if (f.isDirectory()) {
mergeFiles(Stream.of(f.listFiles()).map(File::getAbsolutePath).toArray(String[]::new), truststore, false);
} else {
if (file.endsWith(".p12") || file.endsWith(".pfx")) {
mergeTrustStore(truststore, file, loadStore(file, PKCS12, null));
} else {
mergePemFile(truststore, file, topLevel);
}
}
}
}
static KeyStore createPkcs12KeyStore() {
try {
KeyStore truststore = KeyStore.getInstance(PKCS12);
truststore.load(null, null);
return truststore;
} catch (Exception e) {
throw new RuntimeException("Failed to initialize truststore: cannot create a PKCS12 keystore", e);
}
}
/**
* Include the default truststore, if it can be found.
* <p>
* The existing system properties will be preserved so that this logic can be rerun without consuming
* the newly created merged truststore.
*/
static void includeDefaultTruststore(KeyStore truststore) {
String originalTruststoreKey = TruststoreBuilder.SYSTEM_TRUSTSTORE_KEY + ".orig";
String originalTruststoreTypeKey = TruststoreBuilder.SYSTEM_TRUSTSTORE_TYPE_KEY + ".orig";
String originalTruststorePasswordKey = TruststoreBuilder.SYSTEM_TRUSTSTORE_PASSWORD_KEY + ".orig";
String trustStorePath = System.getProperty(originalTruststoreKey);
String type = PKCS12;
String password = null;
File defaultTrustStore = null;
if (trustStorePath == null) {
trustStorePath = System.getProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_KEY);
if (trustStorePath == null) {
defaultTrustStore = getJRETruststore();
} else {
type = System.getProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_TYPE_KEY, KeyStore.getDefaultType());
password = System.getProperty(TruststoreBuilder.SYSTEM_TRUSTSTORE_PASSWORD_KEY);
// save the original information
System.setProperty(originalTruststoreKey, trustStorePath);
System.setProperty(originalTruststoreTypeKey, type);
if (password == null) {
System.getProperties().remove(originalTruststorePasswordKey);
} else {
System.setProperty(originalTruststorePasswordKey, password);
}
defaultTrustStore = new File(trustStorePath);
}
} else {
type = System.getProperty(originalTruststoreTypeKey);
password = System.getProperty(originalTruststorePasswordKey);
defaultTrustStore = new File(trustStorePath);
}
if (defaultTrustStore.exists()) {
String path = defaultTrustStore.getAbsolutePath();
mergeTrustStore(truststore, path,
loadStore(path, type, Optional.ofNullable(password).map(String::toCharArray).orElse(null)));
} else {
LOGGER.warnf("Default truststore was to be included, but could not be found at: %s", defaultTrustStore);
}
}
static File getJRETruststore() {
// try jre locations - there doesn't seem to be a good default mechanism for this
String securityDirectory = System.getProperty("java.home") + File.separator + "lib" + File.separator
+ "security";
File jssecacertsFile = new File(securityDirectory, "jssecacerts");
if (jssecacertsFile.exists() && jssecacertsFile.isFile()) {
return jssecacertsFile;
}
return new File(securityDirectory, "cacerts");
}
static KeyStore loadStore(String path, String type, char[] password) {
try (InputStream is = new FileInputStream(path)) {
KeyStore ks = KeyStore.getInstance(type);
ks.load(is, password);
return ks;
} catch (Exception e) {
throw new RuntimeException(
"Failed to initialize truststore: " + new File(path).getAbsolutePath() + ", type: " + type, e);
}
}
private static void mergePemFile(KeyStore truststore, String file, boolean isPem) {
try (FileInputStream pemInputStream = new FileInputStream(file)) {
CertificateFactory certFactory = CertificateFactory.getInstance("X509");
boolean loadedAny = false;
while (pemInputStream.available() > 0) {
X509Certificate cert;
try {
cert = (X509Certificate) certFactory.generateCertificate(pemInputStream);
loadedAny = true;
} catch (CertificateException e) {
if (pemInputStream.available() > 0 || !loadedAny) {
// any remaining input means there is an actual problem with the key contents or
// file format
if (isPem) {
throw e;
}
LOGGER.infof(e,
"The file %s may not be in PEM format, it will not be used to create the merged truststore",
new File(file).getAbsolutePath());
continue;
}
LOGGER.debugf(e,
"The trailing entry for %s generated a certificate exception, assuming instead that the file ends with comments",
new File(file).getAbsolutePath());
continue;
}
setCertificateEntry(truststore, cert);
}
} catch (Exception e) {
throw new RuntimeException(
"Failed to initialize truststore, could not merge: " + new File(file).getAbsolutePath(), e);
}
}
private static void setCertificateEntry(KeyStore truststore, Certificate cert) throws KeyStoreException {
String alias = null;
if (cert instanceof X509Certificate) {
X509Certificate x509Cert = (X509Certificate)cert;
// use an alias that should be unique, yet deterministic
alias = x509Cert.getSubjectX500Principal().getName() + "_" + x509Cert.getSerialNumber().toString(16);
} else {
// isn't expected
alias = String.valueOf(Collections.list(truststore.aliases()).size());
}
truststore.setCertificateEntry(alias, cert);
}
private static void mergeTrustStore(KeyStore truststore, String file, KeyStore additionalStore) {
try {
for (String alias : Collections.list(additionalStore.aliases())) {
if (additionalStore.isCertificateEntry(alias)) {
setCertificateEntry(truststore, additionalStore.getCertificate(alias));
}
}
} catch (Exception e) {
throw new RuntimeException(
"Failed to initialize truststore, could not merge: " + new File(file).getAbsolutePath(), e);
}
}
}

View file

@ -18,7 +18,6 @@
package org.keycloak.connections.httpclient;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.InetAddress;
@ -26,7 +25,6 @@ import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import javax.net.ssl.SSLPeerUnverifiedException;
@ -39,11 +37,7 @@ import org.junit.Test;
import org.keycloak.models.KeycloakSession;
import org.keycloak.services.DefaultKeycloakSession;
import org.keycloak.services.DefaultKeycloakSessionFactory;
import org.keycloak.services.util.JsonConfigProvider;
import org.keycloak.services.util.JsonConfigProvider.JsonScope;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.keycloak.utils.ScopeUtil;
public class DefaultHttpClientFactoryTest {
private static final String DISABLE_TRUST_MANAGER_PROPERTY = "disable-trust-manager";
@ -54,12 +48,12 @@ public class DefaultHttpClientFactoryTest {
Map<String, String> values = new HashMap<>();
values.put(DISABLE_TRUST_MANAGER_PROPERTY, "true");
DefaultHttpClientFactory factory = new DefaultHttpClientFactory();
factory.init(scope(values));
factory.init(ScopeUtil.createScope(values));
KeycloakSession session = new DefaultKeycloakSession(new DefaultKeycloakSessionFactory());
HttpClientProvider provider = factory.create(session);
Optional<String> testURL = getTestURL();
Assume.assumeTrue( "Could not get test url for domain", testURL.isPresent() );
try (CloseableHttpClient httpClient = (CloseableHttpClient) provider.getHttpClient();
try (CloseableHttpClient httpClient = provider.getHttpClient();
CloseableHttpResponse response = httpClient.execute(new HttpGet(testURL.get()))) {
assertEquals(HttpStatus.SC_NOT_FOUND,response.getStatusLine().getStatusCode());
}
@ -68,42 +62,16 @@ public class DefaultHttpClientFactoryTest {
@Test(expected = SSLPeerUnverifiedException.class)
public void createHttpClientProviderWithUnvailableURL() throws IOException {
DefaultHttpClientFactory factory = new DefaultHttpClientFactory();
factory.init(scope(new HashMap<>()));
factory.init(ScopeUtil.createScope(new HashMap<>()));
KeycloakSession session = new DefaultKeycloakSession(new DefaultKeycloakSessionFactory());
HttpClientProvider provider = factory.create(session);
try (CloseableHttpClient httpClient = (CloseableHttpClient) provider.getHttpClient()) {
try (CloseableHttpClient httpClient = provider.getHttpClient()) {
Optional<String> testURL = getTestURL();
Assume.assumeTrue("Could not get test url for domain", testURL.isPresent());
httpClient.execute(new HttpGet(testURL.get()));
}
}
private JsonScope scope(Map<String, String> properties) {
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode config = mapper.readTree(json(properties));
return new JsonConfigProvider(config,new Properties()).new JsonScope(config);
} catch (IOException e) {
fail("Could not parse json");
}
return null;
}
private String json(Map<String, String> properties) {
String[] params = properties.entrySet().stream().map(e -> param(e.getKey(), e.getValue())).toArray(String[]::new);
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append(String.join(",", params));
sb.append("}");
return sb.toString();
}
private String param(String key, String value) {
return "\"" + key + "\"" + " : " + "\"" + value + "\"";
}
private Optional<String> getTestURL() {
try {
// Convert domain name to ip to make request by ip

View file

@ -16,8 +16,6 @@
*/
package org.keycloak.protocol.saml.profile.util;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
@ -28,8 +26,6 @@ import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.xml.soap.SOAPException;
import jakarta.xml.soap.SOAPMessage;
@ -57,8 +53,7 @@ import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
import org.keycloak.services.DefaultKeycloakSession;
import org.keycloak.services.DefaultKeycloakSessionFactory;
import org.keycloak.services.util.JsonConfigProvider;
import org.keycloak.services.util.JsonConfigProvider.JsonScope;
import org.keycloak.utils.ScopeUtil;
import org.w3c.dom.Document;
/**
@ -101,33 +96,6 @@ public class SoapTest {
server.stop(0);
}
private String param(String key, String value) {
return "\"" + key + "\"" + " : " + "\"" + value + "\"";
}
private String json(Map<String, String> properties) {
String[] params = properties.entrySet().stream().map(e -> param(e.getKey(), e.getValue())).toArray(String[]::new);
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append(String.join(",", params));
sb.append("}");
return sb.toString();
}
private JsonScope createScope(Map<String, String> properties) {
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode config = mapper.readTree(json(properties));
return new JsonConfigProvider(config, new Properties()).new JsonScope(config);
} catch (IOException e) {
Assert.fail("Could not parse json");
}
return null;
}
private LogoutRequestType createLogoutRequestType() throws ConfigurationException {
NameIDType nameId = new NameIDType();
nameId.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get()));
@ -181,9 +149,9 @@ public class SoapTest {
@Override
public Config.Scope scope(String... scope) {
if (scope.length == 2 && "connectionsHttpClient".equals(scope[0]) && "default".equals(scope[1])) {
return createScope(Collections.singletonMap("proxy-mappings", "localhost;http://localhost:8281"));
return ScopeUtil.createScope(Collections.singletonMap("proxy-mappings", "localhost;http://localhost:8281"));
}
return createScope(new HashMap<>());
return ScopeUtil.createScope(new HashMap<>());
}
});
DefaultKeycloakSessionFactory sessionFactory = new DefaultKeycloakSessionFactory();

View file

@ -0,0 +1,54 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.truststore;
import org.junit.Test;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import org.keycloak.utils.ScopeUtil;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class FileTruststoreProviderFactoryTest {
@Test
public void testFallbackToSystemTruststore() throws IOException {
FileTruststoreProviderFactory factory = new FileTruststoreProviderFactory();
factory.init(ScopeUtil.createScope(new HashMap<>()));
TruststoreProvider provider = factory.create(null);
assertNotNull(provider.getTruststore());
assertEquals(HostnameVerificationPolicy.WILDCARD, provider.getPolicy());
}
@Test
public void testFallbackToSystemTruststoreWithHostnameVerification() throws IOException {
Map<String, String> values = new HashMap<>();
values.put(FileTruststoreProviderFactory.HOSTNAME_VERIFICATION_POLICY,
HostnameVerificationPolicy.ANY.name());
FileTruststoreProviderFactory factory = new FileTruststoreProviderFactory();
factory.init(ScopeUtil.createScope(values));
TruststoreProvider provider = factory.create(null);
assertNotNull(provider.getTruststore());
assertEquals(HostnameVerificationPolicy.ANY, provider.getPolicy());
}
}

View file

@ -0,0 +1,74 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.truststore;
import org.junit.Test;
import java.io.File;
import java.net.URL;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
public class TruststoreBuilderTest {
@Test
public void testMergedTrustStore() throws Exception {
URL url = TruststoreBuilderTest.class.getResource("/truststores/keycloak.pem");
KeyStore storeWithoutDefaults = TruststoreBuilder.createMergedTruststore(new String[] { url.getPath() }, false);
ArrayList<String> storeWithoutDefaultsAliases = Collections.list(storeWithoutDefaults.aliases());
assertEquals(2, storeWithoutDefaultsAliases.size());
KeyStore storeWithDefaults = TruststoreBuilder.createMergedTruststore(new String[] { url.getPath() }, true);
ArrayList<String> storeWithDefaultsAliases = Collections.list(storeWithDefaults.aliases());
int certs = storeWithDefaultsAliases.size();
assertTrue(certs > 2);
assertTrue(storeWithDefaultsAliases.containsAll(storeWithoutDefaultsAliases));
// saving / loading should provide the certs even without a password
char[] password = null;
File saved = TruststoreBuilder.saveTruststore(storeWithDefaults, "target", password);
KeyStore savedLoaded = TruststoreBuilder.loadStore(saved.getAbsolutePath(), TruststoreBuilder.PKCS12, password);
assertEquals(certs, Collections.list(savedLoaded.aliases()).size());
}
@Test
public void testMergedTrustStoreFromDirectory() throws Exception {
URL url = TruststoreBuilderTest.class.getResource("/truststores/keycloak.pem");
KeyStore storeWithoutDefaults = TruststoreBuilder
.createMergedTruststore(new String[] { new File(url.getPath()).getParent() }, false);
ArrayList<String> storeWithoutDefaultsAliases = Collections.list(storeWithoutDefaults.aliases());
assertEquals(2, storeWithoutDefaultsAliases.size());
}
@Test
public void testFailsWithInvalidFile() throws Exception {
URL url = TruststoreBuilderTest.class.getResource("/truststores/invalid");
assertThrows(RuntimeException.class, () -> TruststoreBuilder
.createMergedTruststore(new String[] { new File(url.getPath()).getAbsolutePath() }, false));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright 2023 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.utils;
import org.junit.Assert;
import org.keycloak.services.util.JsonConfigProvider;
import org.keycloak.services.util.JsonConfigProvider.JsonScope;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class ScopeUtil {
public static JsonScope createScope(Map<String, String> properties) {
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode config = mapper.readTree(json(properties));
return new JsonConfigProvider(config, new Properties()).new JsonScope(config);
} catch (IOException e) {
Assert.fail("Could not parse json");
}
return null;
}
static String json(Map<String, String> properties) {
String[] params = properties.entrySet().stream().map(e -> param(e.getKey(), e.getValue())).toArray(String[]::new);
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append(String.join(",", params));
sb.append("}");
return sb.toString();
}
static String param(String key, String value) {
return "\"" + key + "\"" + " : " + "\"" + value + "\"";
}
}

View file

@ -0,0 +1 @@
I am not a PEM file

View file

@ -0,0 +1,53 @@
-----BEGIN CERTIFICATE-----
MIIF/jCCA+agAwIBAgIJAOMEN39fZf7uMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYDVQQGEwJVUzEL
MAkGA1UECAwCTUExDzANBgNVBAcMBkJvc3RvbjEQMA4GA1UECgwHUmVkIEhhdDERMA8GA1UECwwI
S2V5Y2xvYWsxFDASBgNVBAMMC0tleWNsb2FrIENBMSMwIQYJKoZIhvcNAQkBFhRjb250YWN0QGtl
eWNsb2FrLm9yZzAeFw0xODAyMjAxOTQ3NTFaFw00NTA3MDgxOTQ3NTFaMIGLMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCTUExDzANBgNVBAcMBkJvc3RvbjEQMA4GA1UECgwHUmVkIEhhdDERMA8GA1UE
CwwIS2V5Y2xvYWsxFDASBgNVBAMMC0tleWNsb2FrIENBMSMwIQYJKoZIhvcNAQkBFhRjb250YWN0
QGtleWNsb2FrLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJlGjg05FzCm3f3Y
dIbMHNYuORfiP2n6YhX7vQyDjF/4gh7EYEYgE7spJ864/DySQenJ55Jn22K/1MQ1rOHcqfTioIgN
3eEAyyuMDx60KU3frMBRYeCgLJVZQHr06x+Sh/+SbbIYq/558+g/6PSZjmPBindHsPzGuBPaLOW4
Jz47CA73L/su2qnJGeAiUaK/tXmANs1bqJbiNRDr9IJFkdusx1mql2ElfknJT8U+LBPOOID/S7Xd
83SKtpFIQ8Vikb6C0SKnopOJiG2uWg5g7CYlNYxJpAM25zhDqp71bl8zOsIL2tFfUAvvoBnhN31k
DIl8RZJ5ELnh+t5SCfwbgdfMzS7uht8qVTeZ0/BG80Lzl1gfzNR8q45gsKC97mg7Voj68kt2aZr+
E3Ng1guK69gePMxCpqLyjwlKz187mNUme+zxg2gL2egs4M6uffqsEd0c5QryrRSTcIXi8Bim6PDh
L93dBsenAIg25DOJNA6Vt2LELoe9w0TkL48UwUvU6GYB7/zM/z3EW45ZkRhHWK+HZppqDAb05lgJ
eeKUxxdUSy+ot7ls6cSqACYofVjPoVHPD5Ncx+6NGHPGM5N3FGvMMh64PYpChyVWDTEfrZIS7Yyj
9Iz/2eCxV3cOcO4bU0K6kx/dWRic5B5ymVtRME93+Of/hQuta4uLhlo8ZxRpAgMBAAGjYzBhMB0G
A1UdDgQWBBQiuPS7cwDHKT+TgKX2HFICast6UjAfBgNVHSMEGDAWgBQiuPS7cwDHKT+TgKX2HFIC
ast6UjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEA
VCVXdx79ooKyOaL+S49S4agP7mE4IxuDefDwQ2dm996wpk3nntg0y54Auu1Y2plJirBhTvYZ1Red
LNBMVBypm6BQpNn37u5TI39/FYsoGFPINu1EzLTYl0bFKc0w7UFlFusje9zXLWISm8uTNzxJ1RGL
rcnv9gfiXPKxAmN0cz9WY0vm+0+OV50HvLyUyqGKxyWmt2ek4jV+oEhsMMSO/MVNNXHEo2MAGcA2
3XPe7FZkiFB1suDIMzzUFCrRBtoZjYSUeyN9Pd0Yg3twl96CLqld4xFjsKMIsz0ACGRI8OpzeHAs
ePH4yS94E6nLwWH9YTi6pgTtoXSaVBLvIYpVHi8UAyIBFNqLMCukoq0OBlOdkO0zescmpEtp8GiU
WMuB7x+kkaSxmsujEfL3mRWshkqaz/ZHPKXaNtPBUtIMjQnTMBF/wQjZxCGAps8dOMZ9pYnZcmVz
0KeXpBJe1j+47MhItgt1wQNoyr4iBaxE3fAF/Arr/IZtIf0erXOjc7P6dEQW+WiKWvEA5Mp+4tV3
Zj2pwSSX5bKDKx4RAkoW1jLTE1KN5RWvF8phStLty83gTd5wgykFSl65Lu7KIBW9HH3LIK46fb+c
OBOZfSn3mdQXrbuXNUXgbhrsetnBfPNMAkJjaBQLNTxebIvXndiTIEsWqHS7h1x+kBkDOKhwSCc=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEsTCCApmgAwIBAgICC7kwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVTMQswCQYDVQQI
DAJNQTEPMA0GA1UEBwwGQm9zdG9uMRAwDgYDVQQKDAdSZWQgSGF0MREwDwYDVQQLDAhLZXljbG9h
azEUMBIGA1UEAwwLS2V5Y2xvYWsgQ0ExIzAhBgkqhkiG9w0BCQEWFGNvbnRhY3RAa2V5Y2xvYWsu
b3JnMB4XDTE5MDMyMTE4MTk1MFoXDTQ2MDgwNjE4MTk1MFowZDELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAk1BMRAwDgYDVQQKDAdSZWQgSGF0MREwDwYDVQQLDAhLZXljbG9hazEjMCEGA1UEAwwaS2V5
Y2xvYWsgSW50ZXJtZWRpYXRlIENBIDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD1
afusL2MqMMxg20HTGyVt5nxc9MvpzU9yWhKyper9hh/iEDkH06SZ+vInUWGTeRfGmoA3W+IGF4Tz
SFO2BjOLz6bowNTqpWONZAK0swMauE23sbxA7XfKxmIt5pDkQWAWb2kzLoKEXkbmdlF+O/qcM8i+
1U7fpg1NjQI1DHvBVMvul/aGyzP6q/HjNEg+7o3y21T/3gq/Yma9L+awX1wLLxtDlSGjP1Q2C19w
87ijUIwFUo7AzTOn03SIt+Pfc1cdIsmjUG2lDqJTyo/VuqmfWWBMm6p+Ya/Z4Nipk87nxoW60y4E
jRL7vxx9vyWiRUhP/2pEE5y9LQ0uzxxA4kIPAgMBAAGjRTBDMB0GA1UdDgQWBBQYXI8JjLfLFM+o
Cghx8t/R+2iv0zASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B
AQsFAAOCAgEAB5SrTyWz95GqgG0zrtIwJArMY4EUuISGWEgX8GpVyP9xTM1he/vOXqFpAQHtygiq
5yhyrrMJuu5/m0Ca5NZM1NaM6unJr7mIPEKKBP/85Fue/gBe/Q0Vx1VnmxZhszqQT4hLIfR8anLX
gK9w8E6lB4HAXgK+VUzzxXLE43oc8/L9swEnvCKsLHKynexNxKRIZD3GPmLCciOz+101Fb6a0Nc8
+A+5soiQi8gC/K9ygXvxqmHtnrTndZmrtJFOaeXwMDAw7q3j25MkRt4fBPcKX0soBuI6/cTE2veH
GPYXW4QbVswrhJVD/vVuU0VFR1fLnuw9NgDkGz0qoi20x/Ew3HiVi++9EU9YsPgRStcfsCTfth2T
LsPmSFSKeGMR3e+Hr6xr6fcahSl6QmKcI60EHw+kKqQ3bBq7QOxizEuQ0SunRyuEUewnhMT9s7sI
rZ4M2fyiWH3GVm2971J0/ey3NEYSq/Y9fAO6+9xGWlvaps8X5GLs/XYt9HwZNtdb9F3YMNSFi10W
BIKqdpppLT9uuIDSK5S+s5chuychy2TZiCBwKBt1lRdqEZ6J4vMj7M5eIdj8Pmvp+tmL1kewuTfK
aU+2Bpy6l42sYkyMjy7Z0XyMITIBnAf9SmElQPUjq+IIYL6HK/i8mI15AHHIiwm1eaUdbvBKJnQS
0++b0iwvQA4=
-----END CERTIFICATE-----

View file

@ -21,6 +21,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.http.HttpRequest;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import org.keycloak.common.util.HtmlUtils;
import org.keycloak.common.util.Time;
import org.keycloak.component.ComponentModel;
@ -86,7 +87,6 @@ import org.keycloak.testsuite.util.FeatureDeployerUtil;
import org.keycloak.timer.TimerProvider;
import org.keycloak.truststore.FileTruststoreProvider;
import org.keycloak.truststore.FileTruststoreProviderFactory;
import org.keycloak.truststore.HostnameVerificationPolicy;
import org.keycloak.truststore.TruststoreProvider;
import org.keycloak.util.JsonSerialization;
import org.keycloak.utils.MediaType;

View file

@ -19,13 +19,13 @@ package org.keycloak.testsuite.client.resources;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.common.Profile;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.components.TestProvider;
import org.keycloak.testsuite.rest.representation.AuthenticatorState;
import org.keycloak.truststore.HostnameVerificationPolicy;
import org.keycloak.utils.MediaType;
import jakarta.ws.rs.Consumes;

View file

@ -21,6 +21,7 @@ import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.common.enums.HostnameVerificationPolicy;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
@ -39,7 +40,6 @@ import org.keycloak.testsuite.util.AccountHelper;
import org.keycloak.testsuite.util.MailServerConfiguration;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.SslMailServer;
import org.keycloak.truststore.HostnameVerificationPolicy;
import static org.junit.Assert.assertEquals;
import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl;