Unified configuration option format and renaming keycloak.properties to keycloak.conf

Closes #9606
This commit is contained in:
Pedro Igor 2022-01-17 19:14:12 -03:00
parent 8ed7c0544f
commit 0a9387ff4f
47 changed files with 275 additions and 393 deletions

View file

@ -0,0 +1,34 @@
# Basic settings for running in production. Change accordingly before deploying the server.
# Database
# The database vendor.
#db=postgres
# The username of the database user.
#db-username=keycloak
# The password of the database user.
#db-password=password
# The full database JDBC URL. If not provided, a default URL is set based on the selected database vendor.
#db-url=jdbc:postgresql://localhost/keycloak
# Observability
# If the server should expose metrics and healthcheck endpoints.
#metrics-enabled=true
# HTTP
# The file path to a server certificate or certificate chain in PEM format.
#https-certificate-file=${kc.home.dir}conf/server.crt.pem
# The file path to a private key in PEM format.
#https-certificate-key-file=${kc.home.dir}conf/server.key.pem
# The proxy address forwarding mode if the server is behind a reverse proxy.
#proxy=reencrypt
# Hostname for the Keycloak server.
#hostname=myhostname

View file

@ -1,14 +0,0 @@
# Basic settings for running in production. Change accordingly before deploying the server.
# Database
#%prod.db=postgres
#%prod.db.username=keycloak
#%prod.db.password=password
#%prod.db.url=jdbc:postgresql://localhost/keycloak
# Observability
#%prod.metrics.enabled=true
# HTTP
#%prod.spi.hostname.frontend-url=https://localhost:8443
#%prod.https.certificate.file=${kc.home.dir}conf/server.crt.pem
#%prod.https.certificate.key-file=${kc.home.dir}conf/server.key.pem
#%prod.proxy=reencrypt
#%prod.hostname=myhostname

View file

@ -45,7 +45,7 @@ public class CLusteringBuildSteps {
@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep
void configureInfinispan(KeycloakRecorder recorder, BuildProducer<SyntheticBeanBuildItem> syntheticBeanBuildItems, ShutdownContextBuildItem shutdownContext) {
String configFile = getConfigValue("kc.spi.connections-infinispan.quarkus.config-file").getValue();
String configFile = getConfigValue("kc.spi-connections-infinispan-quarkus-config-file").getValue();
if (configFile != null) {
Path configPath = Paths.get(configFile);

View file

@ -414,7 +414,7 @@ class KeycloakProcessor {
@BuildStep(onlyIf = IsDevelopment.class)
void configureDevMode(BuildProducer<HotDeploymentWatchedFileBuildItem> hotFiles) {
hotFiles.produce(new HotDeploymentWatchedFileBuildItem("META-INF/keycloak.properties"));
hotFiles.produce(new HotDeploymentWatchedFileBuildItem("META-INF/keycloak.conf"));
}
private Map<Spi, Map<Class<? extends Provider>, Map<String, ProviderFactory>>> loadFactories(
@ -591,6 +591,6 @@ class KeycloakProcessor {
}
private boolean isMetricsEnabled() {
return Configuration.getOptionalBooleanValue(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat("metrics.enabled")).orElse(false);
return Configuration.getOptionalBooleanValue(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.concat("metrics-enabled")).orElse(false);
}
}

View file

@ -36,7 +36,7 @@ public class KeycloakNegativeHealthCheckTest {
@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource("keycloak.properties", "META-INF/keycloak.properties"));
.addAsResource("keycloak.conf", "META-INF/keycloak.conf"));
@Test
public void testReadinessDown() {

View file

@ -33,7 +33,7 @@ public class KeycloakReadyHealthCheckTest {
@RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource("keycloak.properties", "META-INF/keycloak.properties"));
.addAsResource("keycloak.conf", "META-INF/keycloak.conf"));
@Test
public void testLivenessUp() {

View file

@ -0,0 +1,8 @@
http-enabled=true
cluster=local
hostname-strict=false
hostname-strict-https=false
db=h2-mem
db-username = sa
db-password = keycloak
metrics-enabled=true

View file

@ -1,8 +0,0 @@
http.enabled=true
cluster=local
hostname.strict=false
hostname.strict-https=false
db=h2-mem
db.username = sa
db.password = keycloak
metrics.enabled=true

View file

@ -99,7 +99,7 @@ public final class ExecutionExceptionHandler implements CommandLine.IExecutionEx
private void printErrorHints(PrintWriter errorWriter, Throwable cause) {
if (cause instanceof FileSystemException) {
FileSystemException fse = (FileSystemException) cause;
ConfigValue httpsCertFile = getConfig().getConfigValue("kc.https.certificate.file");
ConfigValue httpsCertFile = getConfig().getConfigValue("kc.https-certificate-file");
if (fse.getFile().equals(Optional.ofNullable(httpsCertFile.getValue()).orElse(null))) {
logError(errorWriter, Messages.httpsConfigurationNotSet().getMessage());

View file

@ -17,12 +17,12 @@
package org.keycloak.quarkus.runtime.cli;
import static io.smallrye.config.common.utils.StringUtil.replaceNonAlphanumericByUnderscores;
import static java.util.Arrays.asList;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_LONG;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_SHORT;
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.hasOptionValue;
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.parseConfigArgs;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuildTimeProperty;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
import static org.keycloak.quarkus.runtime.Environment.isDevMode;
@ -35,7 +35,6 @@ import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIS
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@ -71,7 +70,6 @@ public final class Picocli {
public static final String ARG_PREFIX = "--";
private static final String ARG_KEY_VALUE_SEPARATOR = "=";
public static final String ARG_SHORT_PREFIX = "-";
public static final String ARG_PART_SEPARATOR = "-";
public static final String NO_PARAM_LABEL = "none";
private Picocli() {
@ -348,10 +346,10 @@ public final class Picocli {
.validate(false);
for(PropertyMapper mapper: mappersInCategory) {
String name = ARG_PREFIX + PropertyMappers.toCLIFormat(mapper.getFrom()).substring(3);
String name = mapper.getCliFormat();
String description = mapper.getDescription();
if (description == null || cSpec.optionsMap().containsKey(name) || name.endsWith(ARG_PART_SEPARATOR)) {
if (description == null || cSpec.optionsMap().containsKey(name) || name.endsWith(OPTION_PART_SEPARATOR)) {
//when key is already added or has no description, don't add.
continue;
}
@ -378,10 +376,6 @@ public final class Picocli {
cmd.getOut().println(message);
}
public static String normalizeKey(String key) {
return replaceNonAlphanumericByUnderscores(key).replace('_', '.');
}
public static List<String> parseArgs(String[] rawArgs) {
if (rawArgs.length == 0) {
return List.of();

View file

@ -107,7 +107,7 @@ public final class Main {
@Option(names = { CONFIG_FILE_SHORT_NAME, CONFIG_FILE_LONG_NAME },
arity = "1",
description = "Set the path to a configuration file. By default, configuration properties are read from the \"keycloak.properties\" file in the \"conf\" directory.",
description = "Set the path to a configuration file. By default, configuration properties are read from the \"keycloak.conf\" file in the \"conf\" directory.",
paramLabel = "file")
public void setConfigFile(String path) {
System.setProperty(KeycloakPropertiesConfigSource.KEYCLOAK_CONFIG_FILE_PROP, path);

View file

@ -20,7 +20,6 @@ package org.keycloak.quarkus.runtime.cli.command;
import static org.keycloak.quarkus.runtime.Environment.getCurrentOrPersistedProfile;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfigValue;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getPropertyNames;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.canonicalFormat;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.formatValue;
import java.util.HashSet;
@ -63,8 +62,6 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
printRunTimeConfig(properties, profile);
if (configArgs.equalsIgnoreCase("all")) {
printAllProfilesConfig(properties, profile);
spec.commandLine().getOut().println("Quarkus Configuration:");
properties.get(MicroProfileConfigProvider.NS_QUARKUS).stream().sorted()
.forEachOrdered(this::printProperty);
@ -84,37 +81,10 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
spec.commandLine().getOut().println("Runtime Configuration:");
properties.get(MicroProfileConfigProvider.NS_KEYCLOAK).stream().sorted()
.filter(name -> {
String canonicalFormat = canonicalFormat(name);
if (!canonicalFormat.equals(name)) {
return uniqueNames.add(canonicalFormat);
}
return uniqueNames.add(name);
})
.filter(uniqueNames::add)
.forEachOrdered(this::printProperty);
}
private void printAllProfilesConfig(Map<String, Set<String>> properties, String profile) {
Set<String> profiles = properties.get("%");
if (profiles != null) {
profiles.stream()
.sorted()
.collect(Collectors.groupingBy(s -> s.substring(1, s.indexOf('.'))))
.forEach((p, properties1) -> {
if (p.equals(profile)) {
spec.commandLine().getOut().printf("Profile \"%s\" Configuration (%s):%n", p,
"current");
} else {
spec.commandLine().getOut().printf("Profile \"%s\" Configuration:%n", p);
}
properties1.stream().sorted().forEachOrdered(this::printProperty);
});
}
}
private static Map<String, Set<String>> getPropertiesByGroup() {
Map<String, Set<String>> properties = StreamSupport
.stream(getPropertyNames().spliterator(), false)
@ -147,8 +117,7 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
}
private void printProperty(String property) {
String canonicalFormat = canonicalFormat(property);
ConfigValue configValue = getConfigValue(canonicalFormat);
ConfigValue configValue = getConfigValue(property);
if (configValue.getValue() == null) {
configValue = getConfigValue(property);

View file

@ -21,6 +21,8 @@ import static java.util.Arrays.asList;
import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_SHORT_PREFIX;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_LONG;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_SHORT;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR_CHAR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getMappedPropertyName;
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
@ -97,7 +99,7 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
return value;
}
return properties.get(propertyName.replace('-', '.'));
return properties.get(propertyName.replace(OPTION_PART_SEPARATOR_CHAR, '.'));
}
private static Map<String, String> parseArgument() {
@ -127,9 +129,6 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
if (mapper != null) {
properties.put(mapper.getFrom(), value);
}
// to make lookup easier, we normalize the key
properties.put(Picocli.normalizeKey(key), value);
}
});

View file

@ -17,17 +17,15 @@
package org.keycloak.quarkus.runtime.configuration;
import static io.smallrye.config.common.utils.StringUtil.replaceNonAlphanumericByUnderscores;
import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.toCLIFormat;
import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_PREFIX;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import io.smallrye.config.ConfigValue;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigProviderResolver;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.eclipse.microprofile.config.spi.ConfigSource;
@ -40,6 +38,9 @@ import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
*/
public final class Configuration {
public static final char OPTION_PART_SEPARATOR_CHAR = '-';
public static final String OPTION_PART_SEPARATOR = String.valueOf(OPTION_PART_SEPARATOR_CHAR);
private Configuration() {
}
@ -98,17 +99,14 @@ public final class Configuration {
}
public static String getMappedPropertyName(String key) {
for (PropertyMapper mapper : PropertyMappers.getMappers()) {
String mappedProperty = mapper.getFrom();
List<String> expectedFormats = Arrays.asList(mappedProperty, toCLIFormat(mappedProperty), mappedProperty.toUpperCase().replace('.', '_').replace('-', '_'));
PropertyMapper mapper = PropertyMappers.getMapper(key);
if (expectedFormats.contains(key)) {
// we also need to make sure the target property is available when defined such as when defining alias for provider config (no spi-prefix).
return mapper.getTo() == null ? mappedProperty : mapper.getTo();
}
if (mapper == null) {
return key;
}
return key;
// we also need to make sure the target property is available when defined such as when defining alias for provider config (no spi-prefix).
return mapper.getTo() == null ? mapper.getFrom() : mapper.getTo();
}
public static Optional<String> getRuntimeProperty(String name) {
@ -131,6 +129,14 @@ public final class Configuration {
return Optional.empty();
}
public static String toEnvVarFormat(String key) {
return replaceNonAlphanumericByUnderscores(key).toUpperCase();
}
public static String toCliFormat(String key) {
return ARG_PREFIX + key;
}
private static String getValue(ConfigSource configSource, String name) {
String value = configSource.getValue(name);

View file

@ -33,10 +33,12 @@ public class KcEnvConfigSource extends EnvConfigSource {
private static Map<String, String> buildProperties() {
Map<String, String> properties = new HashMap<>();
String kcPrefix = replaceNonAlphanumericByUnderscores(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.toUpperCase());
for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
String key = entry.getKey();
if (key.startsWith(replaceNonAlphanumericByUnderscores(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.toUpperCase()))) {
if (key.startsWith(kcPrefix)) {
properties.put(getMappedPropertyName(key), entry.getValue());
}
}

View file

@ -42,7 +42,6 @@ public class KeycloakConfigSourceProvider implements ConfigSourceProvider {
}
CONFIG_SOURCES.add(new ConfigArgsConfigSource());
CONFIG_SOURCES.add(new SysPropConfigSource());
CONFIG_SOURCES.add(new KcEnvConfigSource());
CONFIG_SOURCES.add(PersistedConfigSource.getInstance());

View file

@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import org.eclipse.microprofile.config.spi.ConfigSource;
@ -45,30 +46,30 @@ import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvi
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_QUARKUS;
/**
* A configuration source for {@code keycloak.properties}.
* A configuration source for {@code keycloak.conf}.
*/
public class KeycloakPropertiesConfigSource extends AbstractLocationConfigSourceLoader {
private static final Pattern DOT_SPLIT = Pattern.compile("\\.");
private static final String KEYCLOAK_CONFIG_FILE_ENV = "KC_CONFIG_FILE";
private static final String KEYCLOAK_PROPERTIES = "keycloak.properties";
private static final String KEYCLOAK_CONF_FILE = "keycloak.conf";
public static final String KEYCLOAK_CONFIG_FILE_PROP = NS_KEYCLOAK_PREFIX + "config.file";
@Override
protected String[] getFileExtensions() {
return new String[] { "properties" };
return new String[] { "conf" };
}
@Override
protected ConfigSource loadConfigSource(URL url, int ordinal) throws IOException {
return new PropertiesConfigSource(transform(ConfigSourceUtil.urlToMap(url)), KEYCLOAK_PROPERTIES, ordinal);
return new PropertiesConfigSource(transform(ConfigSourceUtil.urlToMap(url)), KEYCLOAK_CONF_FILE, ordinal);
}
public static class InClassPath extends KeycloakPropertiesConfigSource implements ConfigSourceProvider {
@Override
public List<ConfigSource> getConfigSources(final ClassLoader classLoader) {
return loadConfigSources("META-INF/keycloak.properties", 150, classLoader);
return loadConfigSources("META-INF/" + KEYCLOAK_CONF_FILE, 150, classLoader);
}
@Override
@ -122,7 +123,7 @@ public class KeycloakPropertiesConfigSource extends AbstractLocationConfigSource
String homeDir = Environment.getHomeDir();
if (homeDir != null) {
File file = Paths.get(homeDir, "conf", KeycloakPropertiesConfigSource.KEYCLOAK_PROPERTIES).toFile();
File file = Paths.get(homeDir, "conf", KeycloakPropertiesConfigSource.KEYCLOAK_CONF_FILE).toFile();
if (file.exists()) {
filePath = file.getAbsolutePath();

View file

@ -17,6 +17,9 @@
package org.keycloak.quarkus.runtime.configuration;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.toEnvVarFormat;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -60,7 +63,7 @@ public class MicroProfileConfigProvider implements Config.ConfigProvider {
public MicroProfileScope(String... scope) {
this.scope = scope;
this.prefix = String.join(".", ArrayUtils.insert(0, scope, NS_KEYCLOAK, "spi"));
this.prefix = NS_KEYCLOAK_PREFIX + String.join(OPTION_PART_SEPARATOR, ArrayUtils.insert(0, scope, "spi"));
}
@Override
@ -119,14 +122,14 @@ public class MicroProfileConfigProvider implements Config.ConfigProvider {
.filter(new Predicate<String>() {
@Override
public boolean test(String key) {
return key.startsWith(prefix) || key.startsWith(Picocli.normalizeKey(prefix));
return key.startsWith(prefix) || key.startsWith(toEnvVarFormat(prefix));
}
})
.collect(Collectors.toSet());
}
private <T> T getValue(String key, Class<T> clazz, T defaultValue) {
return config.getOptionalValue(toDashCase(prefix.concat(".").concat(key)), clazz).orElse(defaultValue);
return config.getOptionalValue(toDashCase(prefix.concat(OPTION_PART_SEPARATOR).concat(key)), clazz).orElse(defaultValue);
}
}

View file

@ -64,7 +64,7 @@ public final class PersistedConfigSource extends PropertiesConfigSource {
return value;
}
return super.getValue(propertyName.replace('-', '.'));
return super.getValue(propertyName.replace(Configuration.OPTION_PART_SEPARATOR_CHAR, '.'));
}
private static Map<String, String> readProperties() {

View file

@ -1,65 +0,0 @@
/*
* 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.quarkus.runtime.configuration;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.eclipse.microprofile.config.spi.ConfigSource;
/**
* The only reason for this config source is to keep the Keycloak specific properties when configuring the server so that
* they are read again when running the server after the configuration.
*/
public class SysPropConfigSource implements ConfigSource {
private final Map<String, String> properties = new TreeMap<>();
public SysPropConfigSource() {
for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
String key = (String) entry.getKey();
if (key.startsWith(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX)) {
properties.put(key, entry.getValue().toString());
}
}
}
@Override
public Map<String, String> getProperties() {
return properties;
}
@Override
public Set<String> getPropertyNames() {
return properties.keySet();
}
public String getValue(final String propertyName) {
return System.getProperty(propertyName);
}
public String getName() {
return "KcSysPropConfigSource";
}
@Override
public int getOrdinal() {
return 550;
}
}

View file

@ -24,7 +24,7 @@ final class ClusteringPropertyMappers {
.expectedValues("local", "ispn")
.build(),
builder().from("cache-stack")
.to("kc.spi.connections-infinispan.quarkus.stack")
.to("kc.spi-connections-infinispan-quarkus-stack")
.description("Define the default stack to use for cluster communication and node discovery. This option only takes effect "
+ "if 'cache' is set to 'ispn'.")
.defaultValue("udp")
@ -32,9 +32,9 @@ final class ClusteringPropertyMappers {
.isBuildTimeProperty(true)
.expectedValues(Arrays.asList("tcp", "udp", "kubernetes", "ec2", "azure", "google"))
.build(),
builder().from("cache.config-file")
builder().from("cache-config-file")
.mapFrom("cache")
.to("kc.spi.connections-infinispan.quarkus.config-file")
.to("kc.spi-connections-infinispan-quarkus-config-file")
.description("Defines the file from which cache configuration should be loaded from.")
.transformer(new BiFunction<String, ConfigSourceInterceptorContext, String>() {
@Override

View file

@ -23,7 +23,7 @@ final class DatabasePropertyMappers {
.transformer((db, context) -> Database.getDialect(db).orElse(Database.getDialect("h2-file").get()))
.hidden(true)
.build(),
builder().from("db.driver")
builder().from("db-driver")
.mapFrom("db")
.defaultValue(Database.getDriver("h2-file").get())
.to("quarkus.datasource.jdbc.driver")
@ -38,12 +38,12 @@ final class DatabasePropertyMappers {
.paramLabel("vendor")
.expectedValues(asList(Database.getAliases()))
.build(),
builder().from("db.tx-type")
builder().from("db-tx-type")
.defaultValue("xa")
.to("quarkus.datasource.jdbc.transactions")
.hidden(true)
.build(),
builder().from("db.url")
builder().from("db-url")
.to("quarkus.datasource.jdbc.url")
.mapFrom("db")
.transformer((value, context) -> Database.getDefaultUrl(value).orElse(value))
@ -51,48 +51,48 @@ final class DatabasePropertyMappers {
"For instance, if using 'postgres', the default JDBC URL would be 'jdbc:postgresql://localhost/keycloak'. ")
.paramLabel("jdbc-url")
.build(),
builder().from("db.url.host")
.to("kc.db.url.host")
builder().from("db-url-host")
.to("kc.db-url-host")
.description("Sets the hostname of the default JDBC URL of the chosen vendor. If the `db-url` option is set, this option is ignored.")
.paramLabel("hostname")
.build(),
builder().from("db.url.database")
.to("kc.db.url.database")
builder().from("db-url-database")
.to("kc.db-url-database")
.description("Sets the database name of the default JDBC URL of the chosen vendor. If the `db-url` option is set, this option is ignored.")
.paramLabel("dbname")
.build(),
builder().from("db.url.properties")
.to("kc.db.url.properties")
builder().from("db-url-properties")
.to("kc.db-url-properties")
.description("Sets the properties of the default JDBC URL of the chosen vendor. If the `db-url` option is set, this option is ignored.")
.paramLabel("properties")
.build(),
builder().from("db.username")
builder().from("db-username")
.to("quarkus.datasource.username")
.description("The username of the database user.")
.paramLabel("username")
.build(),
builder().from("db.password")
builder().from("db-password")
.to("quarkus.datasource.password")
.description("The password of the database user.")
.paramLabel("password")
.isMasked(true)
.build(),
builder().from("db.schema")
builder().from("db-schema")
.to("quarkus.hibernate-orm.database.default-schema")
.description("The database schema to be used.")
.paramLabel("schema")
.build(),
builder().from("db.pool.initial-size")
builder().from("db-pool-initial-size")
.to("quarkus.datasource.jdbc.initial-size")
.description("The initial size of the connection pool.")
.paramLabel("size")
.build(),
builder().from("db.pool.min-size")
builder().from("db-pool-min-size")
.to("quarkus.datasource.jdbc.min-size")
.description("The minimal size of the connection pool.")
.paramLabel("size")
.build(),
builder().from("db.pool.max-size")
builder().from("db-pool-max-size")
.to("quarkus.datasource.jdbc.max-size")
.defaultValue(String.valueOf(100))
.description("The maximum size of the connection pool.")

View file

@ -8,35 +8,35 @@ final class HostnamePropertyMappers {
public static PropertyMapper[] getHostnamePropertyMappers() {
return new PropertyMapper[] {
builder().from("hostname")
.to("kc.spi.hostname.default.hostname")
.to("kc.spi-hostname-default-hostname")
.description("Hostname for the Keycloak server.")
.paramLabel("hostname")
.build(),
builder().from("hostname.admin")
.to("kc.spi.hostname.default.admin")
builder().from("hostname-admin")
.to("kc.spi-hostname-default-admin")
.description("Overrides the hostname for the admin console and APIs.")
.paramLabel("url")
.build(),
builder().from("hostname.strict")
.to("kc.spi.hostname.default.strict")
builder().from("hostname-strict")
.to("kc.spi-hostname-default-strict")
.description("Disables dynamically resolving the hostname from request headers. Should always be set to true in production, unless proxy verifies the Host header.")
.type(Boolean.class)
.defaultValue(Boolean.TRUE.toString())
.build(),
builder().from("hostname.strict-https")
.to("kc.spi.hostname.default.strict-https")
builder().from("hostname-strict-https")
.to("kc.spi-hostname-default-strict-https")
.description("Forces URLs to use HTTPS. Only needed if proxy does not properly set the X-Forwarded-Proto header.")
.hidden(true)
.defaultValue(Boolean.TRUE.toString())
.type(Boolean.class)
.build(),
builder().from("hostname.strict-backchannel")
.to("kc.spi.hostname.default.strict-backchannel")
builder().from("hostname-strict-backchannel")
.to("kc.spi-hostname-default-strict-backchannel")
.description("By default backchannel URLs are dynamically resolved from request headers to allow internal an external applications. If all applications use the public URL this option should be enabled.")
.type(Boolean.class)
.build(),
builder().from("hostname.path")
.to("kc.spi.hostname.default.path")
builder().from("hostname-path")
.to("kc.spi-hostname-default-path")
.description("This should be set if proxy uses a different context-path for Keycloak.")
.paramLabel("path")
.build()

View file

@ -19,7 +19,7 @@ final class HttpPropertyMappers {
public static PropertyMapper[] getHttpPropertyMappers() {
return new PropertyMapper[] {
builder().from("http.enabled")
builder().from("http-enabled")
.to("quarkus.http.insecure-requests")
.defaultValue(Boolean.FALSE.toString())
.transformer(HttpPropertyMappers::getHttpEnabledTransformer)
@ -27,90 +27,90 @@ final class HttpPropertyMappers {
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.expectedValues(Arrays.asList(Boolean.TRUE.toString(), Boolean.FALSE.toString()))
.build(),
builder().from("http.host")
builder().from("http-host")
.to("quarkus.http.host")
.defaultValue("0.0.0.0")
.description("The used HTTP Host.")
.paramLabel("host")
.build(),
builder().from("http.relative-path")
builder().from("http-relative-path")
.to("quarkus.http.root-path")
.defaultValue("/")
.description("Set the path relative to '/' for serving resources.")
.paramLabel("path")
.isBuildTimeProperty(true)
.build(),
builder().from("http.port")
builder().from("http-port")
.to("quarkus.http.port")
.defaultValue(String.valueOf(8080))
.description("The used HTTP port.")
.paramLabel("port")
.build(),
builder().from("https.port")
builder().from("https-port")
.to("quarkus.http.ssl-port")
.defaultValue(String.valueOf(8443))
.description("The used HTTPS port.")
.paramLabel("port")
.build(),
builder().from("https.client-auth")
builder().from("https-client-auth")
.to("quarkus.http.ssl.client-auth")
.defaultValue("none")
.description("Configures the server to require/request client authentication. Possible Values: none, request, required.")
.paramLabel("auth")
.expectedValues(Arrays.asList("none", "request", "required"))
.build(),
builder().from("https.cipher-suites")
builder().from("https-cipher-suites")
.to("quarkus.http.ssl.cipher-suites")
.description("The cipher suites to use. If none is given, a reasonable default is selected.")
.paramLabel("ciphers")
.build(),
builder().from("https.protocols")
builder().from("https-protocols")
.to("quarkus.http.ssl.protocols")
.description("The list of protocols to explicitly enable.")
.paramLabel("protocols")
.defaultValue("TLSv1.3")
.build(),
builder().from("https.certificate.file")
builder().from("https-certificate-file")
.to("quarkus.http.ssl.certificate.file")
.description("The file path to a server certificate or certificate chain in PEM format.")
.paramLabel("file")
.build(),
builder().from("https.certificate.key-file")
builder().from("https-certificate-key-file")
.to("quarkus.http.ssl.certificate.key-file")
.description("The file path to a private key in PEM format.")
.paramLabel("file")
.build(),
builder().from("https.key-store.file")
builder().from("https-key-store-file")
.to("quarkus.http.ssl.certificate.key-store-file")
.defaultValue(getDefaultKeystorePathValue())
.description("The key store which holds the certificate information instead of specifying separate files.")
.paramLabel("file")
.build(),
builder().from("https.key-store.password")
builder().from("https-key-store-password")
.to("quarkus.http.ssl.certificate.key-store-password")
.description("The password of the key store file.")
.defaultValue("password")
.paramLabel("password")
.isMasked(true)
.build(),
builder().from("https.key-store.type")
builder().from("https-key-store-type")
.to("quarkus.http.ssl.certificate.key-store-file-type")
.description("The type of the key store file. " +
"If not given, the type is automatically detected based on the file name.")
.paramLabel("type")
.build(),
builder().from("https.trust-store.file")
builder().from("https-trust-store-file")
.to("quarkus.http.ssl.certificate.trust-store-file")
.description("The trust store which holds the certificate information of the certificates to trust.")
.paramLabel("file")
.build(),
builder().from("https.trust-store.password")
builder().from("https-trust-store-password")
.to("quarkus.http.ssl.certificate.trust-store-password")
.description("The password of the trust store file.")
.paramLabel("password")
.isMasked(true)
.build(),
builder().from("https.trust-store.type")
builder().from("https-trust-store-type")
.to("quarkus.http.ssl.certificate.trust-store-file-type")
.defaultValue(getDefaultKeystorePathValue())
.description("The type of the trust store file. " +
@ -131,7 +131,7 @@ final class HttpPropertyMappers {
}
if (!enabled) {
ConfigValue proceed = context.proceed("kc.https.certificate.file");
ConfigValue proceed = context.proceed("kc.https-certificate-file");
if (proceed == null || proceed.getValue() == null) {
proceed = getMapper("quarkus.http.ssl.certificate.key-store-file").getConfigValue(context);

View file

@ -9,7 +9,7 @@ final class MetricsPropertyMappers {
public static PropertyMapper[] getMetricsPropertyMappers() {
return new PropertyMapper[] {
builder().from("metrics.enabled")
builder().from("metrics-enabled")
.to("quarkus.datasource.metrics.enabled")
.isBuildTimeProperty(true)
.defaultValue(Boolean.FALSE.toString())

View file

@ -16,13 +16,18 @@
*/
package org.keycloak.quarkus.runtime.configuration.mappers;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR_CHAR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.toCliFormat;
import static org.keycloak.quarkus.runtime.configuration.Configuration.toEnvVarFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.BiFunction;
import io.smallrye.config.ConfigSourceInterceptorContext;
import io.smallrye.config.ConfigValue;
import org.keycloak.quarkus.runtime.cli.Picocli;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
public class PropertyMapper {
@ -47,9 +52,9 @@ public class PropertyMapper {
private final ConfigCategory category;
private final String paramLabel;
private final boolean hidden;
private final String envVarFormat;
private String cliFormat;
PropertyMapper(String from, String to, String defaultValue, BiFunction<String, ConfigSourceInterceptorContext, String> mapper,
String mapFrom, boolean buildTime, String description, String paramLabel, boolean mask, Iterable<String> expectedValues,
ConfigCategory category, boolean hidden) {
@ -65,7 +70,8 @@ public class PropertyMapper {
this.expectedValues = expectedValues == null ? Collections.emptyList() : expectedValues;
this.category = category != null ? category : ConfigCategory.GENERAL;
this.hidden = hidden;
setCliFormat(this.from);
this.cliFormat = toCliFormat(from);
this.envVarFormat = toEnvVarFormat(this.from);
}
public static PropertyMapper.Builder builder(String fromProp, String toProp) {
@ -87,9 +93,9 @@ public class PropertyMapper {
ConfigValue getConfigValue(String name, ConfigSourceInterceptorContext context) {
String from = this.from;
if (to != null && to.endsWith(".")) {
if (to != null && to.endsWith(OPTION_PART_SEPARATOR)) {
// in case mapping is based on prefixes instead of full property names
from = name.replace(to.substring(0, to.lastIndexOf('.')), from.substring(0, from.lastIndexOf('.')));
from = name.replace(to.substring(0, to.lastIndexOf('.')), from.substring(0, from.lastIndexOf(OPTION_PART_SEPARATOR_CHAR)));
}
// try to obtain the value for the property we want to map first
@ -98,7 +104,7 @@ public class PropertyMapper {
if (config == null) {
if (mapFrom != null) {
// if the property we want to map depends on another one, we use the value from the other property to call the mapper
String parentKey = MicroProfileConfigProvider.NS_KEYCLOAK + "." + mapFrom;
String parentKey = MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + mapFrom;
ConfigValue parentValue = context.proceed(parentKey);
if (parentValue == null) {
@ -187,6 +193,10 @@ public class PropertyMapper {
return cliFormat;
}
public String getEnvVarFormat() {
return envVarFormat;
}
boolean isMask() {
return mask;
}
@ -209,10 +219,6 @@ public class PropertyMapper {
return null;
}
private void setCliFormat(String from) {
cliFormat = Picocli.ARG_PREFIX + PropertyMappers.toCLIFormat(from).substring(3);
}
public static class Builder {
private String from;

View file

@ -82,7 +82,7 @@ public final class PropertyMappers {
&& !Environment.PROFILE.equals(name)
&& !"kc.show.config".equals(name)
&& !"kc.show.config.runtime".equals(name)
&& !toCLIFormat("kc.config.file").equals(name);
&& !"kc.config-file".equals(name);
}
private static boolean isSpiBuildTimeProperty(String name) {
@ -93,16 +93,6 @@ public final class PropertyMappers {
return name.startsWith("kc.features");
}
public static String toCLIFormat(String name) {
if (name.indexOf('.') == -1) {
return name;
}
return MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX
.concat(name.substring(3, name.lastIndexOf('.') + 1)
.replaceAll("\\.", "-") + name.substring(name.lastIndexOf('.') + 1));
}
public static List<PropertyMapper> getRuntimeMappers() {
return MAPPERS.values().stream()
.filter(entry -> !entry.isBuildTime()).collect(Collectors.toList());
@ -113,10 +103,6 @@ public final class PropertyMappers {
.filter(PropertyMapper::isBuildTime).collect(Collectors.toList());
}
public static String canonicalFormat(String name) {
return name.replaceAll("-", "\\.");
}
public static String formatValue(String property, String value) {
property = removeProfilePrefixIfNeeded(property);
PropertyMapper mapper = getMapper(property);
@ -170,6 +156,7 @@ public final class PropertyMappers {
super.put(mapper.getTo(), mapper);
super.put(mapper.getFrom(), mapper);
super.put(mapper.getCliFormat(), mapper);
super.put(mapper.getEnvVarFormat(), mapper);
}
}

View file

@ -8,19 +8,19 @@ final class VaultPropertyMappers {
public static PropertyMapper[] getVaultPropertyMappers() {
return new PropertyMapper[] {
builder()
.from("vault.file.path")
.to("kc.spi.vault.files-plaintext.dir")
.from("vault-file-path")
.to("kc.spi-vault-files-plaintext-dir")
.description("If set, secrets can be obtained by reading the content of files within the given path.")
.paramLabel("dir")
.build(),
builder()
.from("vault.hashicorp.")
.from("vault-hashicorp-")
.to("quarkus.vault.")
.description("If set, secrets can be obtained from Hashicorp Vault.")
.build(),
builder()
.from("vault.hashicorp.paths")
.to("kc.spi.vault.hashicorp.paths")
.from("vault-hashicorp-paths")
.to("kc.spi-vault-hashicorp-paths")
.description("A set of one or more paths that should be used when looking up secrets.")
.paramLabel("paths")
.build()

View file

@ -210,7 +210,7 @@ public final class DefaultHostnameProvider implements HostnameProvider, Hostname
defaultPath = config.get("path");
noProxy = Configuration.getConfigValue("kc.proxy").getValue().equals("none");
defaultTlsPort = Integer.parseInt(Configuration.getConfigValue("kc.https.port").getValue());
defaultTlsPort = Integer.parseInt(Configuration.getConfigValue("kc.https-port").getValue());
adminHostName = config.get("admin");
strictBackChannel = config.getBoolean("strict-backchannel", false);

View file

@ -100,11 +100,11 @@ public final class Database {
@Override
public String apply(String alias) {
if ("h2-file".equalsIgnoreCase(alias)) {
return "jdbc:h2:file:${kc.home.dir:${kc.db.url.path:~}}" + File.separator + "${kc.data.dir:data}"
return "jdbc:h2:file:${kc.home.dir:${kc.db-url-path:~}}" + File.separator + "${kc.data.dir:data}"
+ File.separator + "h2" + File.separator
+ "keycloakdb${kc.db.url.properties:;;AUTO_SERVER=TRUE}";
+ "keycloakdb${kc.db-url-properties:;;AUTO_SERVER=TRUE}";
}
return "jdbc:h2:mem:keycloakdb${kc.db.url.properties:}";
return "jdbc:h2:mem:keycloakdb${kc.db-url-properties:}";
}
},
asList("liquibase.database.core.H2Database"),
@ -114,13 +114,13 @@ public final class Database {
"com.mysql.cj.jdbc.MysqlXADataSource",
"org.hibernate.dialect.MySQL8Dialect",
"jdbc:mysql://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}",
"jdbc:mysql://${kc.db-url-host:localhost}/${kc.db-url-database:keycloak}${kc.db-url-properties:}",
asList("org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase")
),
MARIADB("mariadb",
"org.mariadb.jdbc.MySQLDataSource",
"org.hibernate.dialect.MariaDBDialect",
"jdbc:mariadb://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}",
"jdbc:mariadb://${kc.db-url-host:localhost}/${kc.db-url-database:keycloak}${kc.db-url-properties:}",
asList("org.keycloak.connections.jpa.updater.liquibase.UpdatedMariaDBDatabase")
),
POSTGRES("postgresql",
@ -134,7 +134,7 @@ public final class Database {
return "io.quarkus.hibernate.orm.runtime.dialect.QuarkusPostgreSQL10Dialect";
}
},
"jdbc:postgresql://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}",
"jdbc:postgresql://${kc.db-url-host:localhost}/${kc.db-url-database:keycloak}${kc.db-url-properties:}",
asList("liquibase.database.core.PostgresDatabase",
"org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase"),
"postgres", "postgres-95"
@ -151,14 +151,14 @@ public final class Database {
return "org.hibernate.dialect.SQLServer2016Dialect";
}
},
"jdbc:sqlserver://${kc.db.url.host:localhost}:1433;databaseName=${kc.db.url.database:keycloak}${kc.db.url.properties:}",
"jdbc:sqlserver://${kc.db-url-host:localhost}:1433;databaseName=${kc.db-url-database:keycloak}${kc.db-url-properties:}",
asList("org.keycloak.quarkus.runtime.storage.database.liquibase.database.CustomMSSQLDatabase"),
"mssql", "mssql-2012"
),
ORACLE("oracle",
"oracle.jdbc.xa.client.OracleXADataSource",
"org.hibernate.dialect.Oracle12cDialect",
"jdbc:oracle:thin:@//${kc.db.url.host:localhost}:1521/${kc.db.url.database:keycloak}",
"jdbc:oracle:thin:@//${kc.db-url-host:localhost}:1521/${kc.db-url-database:keycloak}",
asList("liquibase.database.core.OracleDatabase")
);

View file

@ -176,7 +176,7 @@ public final class QuarkusJpaConnectionProviderFactory implements JpaConnectionP
@Override
public String getSchema() {
return Configuration.getRawValue("kc.db.schema");
return Configuration.getRawValue("kc.db-schema");
}
@Override

View file

@ -74,11 +74,11 @@ public class CacheManagerFactory {
private boolean isStartEagerly() {
// eagerly starts caches by default
return Boolean.parseBoolean(System.getProperty("kc.cache.ispn.start-eagerly", Boolean.TRUE.toString()));
return Boolean.parseBoolean(System.getProperty("kc.cache-ispn-start-eagerly", Boolean.TRUE.toString()));
}
private Integer getStartTimeout() {
return Integer.getInteger("kc.cache.ispn.start-timeout", 120);
return Integer.getInteger("kc.cache-ispn-start-timeout", 120);
}
private void shutdownThreadPool() {

View file

@ -1,27 +1,27 @@
# Default and non-production grade database vendor
db=h2-file
db.username = sa
db.password = keycloak
db-username = sa
db-password = keycloak
# Insecure requests are disabled by default
http.enabled=false
http-enabled=false
# Metrics and healthcheck are disabled by default
metrics.enabled=false
metrics-enabled=false
# Default, and insecure, and non-production grade configuration for the development profile
%dev.http.enabled=true
%dev.hostname.strict=false
%dev.hostname.strict-https=false
%dev.http-enabled=true
%dev.hostname-strict=false
%dev.hostname-strict-https=false
%dev.cache=local
%dev.spi.theme.cache-themes=false
%dev.spi.theme.cache-templates=false
%dev.spi.theme.static-max-age=-1
%dev.spi-theme-cache-themes=false
%dev.spi-theme-cache-templates=false
%dev.spi-theme-static-max-age=-1
# The default configuration when running in import or export mode
%import_export.http.enabled=true
%import_export.hostname.strict=false
%import_export.hostname.strict-https=false
%import_export.http-enabled=true
%import_export.hostname-strict=false
%import_export.hostname-strict-https=false
%import_export.cluster=local
# Logging configuration. INFO is the default level for most of the categories

View file

@ -128,14 +128,14 @@ public class ConfigurationTest {
Config.Scope config = initConfig("vault", FilesPlainTextVaultProviderFactory.PROVIDER_ID);
assertEquals("/foo/bar", config.get("dir"));
assertTrue(config.getPropertyNames()
.contains("kc.spi.vault.".concat(FilesPlainTextVaultProviderFactory.PROVIDER_ID).concat(".dir")));
.contains("kc.spi-vault-".concat(FilesPlainTextVaultProviderFactory.PROVIDER_ID).concat("-dir")));
}
@Test
public void testSysPropPriorityOverEnvVar() {
public void testEnvVarPriorityOverSysProps() {
putEnvVar("KC_SPI_HOSTNAME_DEFAULT_FRONTEND_URL", "http://envvar.unittest");
System.setProperty("kc.spi.hostname.default.frontend-url", "http://propvar.unittest");
assertEquals("http://propvar.unittest", initConfig("hostname", "default").get("frontendUrl"));
System.setProperty("kc.spi-hostname-default-frontend-url", "http://propvar.unittest");
assertEquals("http://envvar.unittest", initConfig("hostname", "default").get("frontendUrl"));
}
@Test
@ -203,13 +203,13 @@ public class ConfigurationTest {
assertEquals("secrets", config.get("dir"));
System.getProperties().remove(CLI_ARGS);
System.setProperty("kc.spi.client-registration.openid-connect.static-jwk-url", "http://c.jwk.url");
System.setProperty("kc.spi-client-registration-openid-connect-static-jwk-url", "http://c.jwk.url");
config = initConfig("client-registration", "openid-connect");
assertEquals(1, config.getPropertyNames().size());
assertEquals("http://c.jwk.url", config.get("static-jwk-url"));
System.getProperties().remove(CLI_ARGS);
System.getProperties().remove("kc.spi.client-registration.openid-connect.static-jwk-url");
System.getProperties().remove("kc.spi-client-registration-openid-connect-static-jwk-url");
putEnvVar("KC_SPI_CLIENT_REGISTRATION_OPENID_CONNECT_STATIC_JWK_URL", "http://c.jwk.url/from-env");
config = initConfig("client-registration", "openid-connect");
assertEquals(1, config.getPropertyNames().size());
@ -279,8 +279,8 @@ public class ConfigurationTest {
@Test
public void testDatabaseProperties() {
System.setProperty("kc.db.url.properties", ";;test=test;test1=test1");
System.setProperty("kc.db.url.path", "test-dir");
System.setProperty("kc.db-url-properties", ";;test=test;test1=test1");
System.setProperty("kc.db-url-path", "test-dir");
System.setProperty(CLI_ARGS, "--db=h2-file");
SmallRyeConfig config = createConfig();
assertEquals(QuarkusH2Dialect.class.getName(), config.getConfigValue("quarkus.hibernate-orm.dialect").getValue());
@ -292,7 +292,7 @@ public class ConfigurationTest {
assertEquals(QuarkusH2Dialect.class.getName(), config.getConfigValue("quarkus.hibernate-orm.dialect").getValue());
assertEquals("jdbc:h2:file:test-dir" + File.separator + "data" + File.separator + "h2" + File.separator + "keycloakdb;;test=test;test1=test1", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
System.setProperty("kc.db.url.properties", "?test=test&test1=test1");
System.setProperty("kc.db-url-properties", "?test=test&test1=test1");
System.setProperty(CLI_ARGS, "--db=mariadb");
config = createConfig();
assertEquals("jdbc:mariadb://localhost/keycloak?test=test&test1=test1", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
@ -307,7 +307,7 @@ public class ConfigurationTest {
System.setProperty(CLI_ARGS, "--db-schema=test-schema");
config = createConfig();
assertEquals("test-schema", config.getConfigValue("kc.db.schema").getValue());
assertEquals("test-schema", config.getConfigValue("kc.db-schema").getValue());
assertEquals("test-schema", config.getConfigValue("quarkus.hibernate-orm.database.default-schema").getValue());
}
@ -368,8 +368,8 @@ public class ConfigurationTest {
@Test
public void testDatabaseDriverSetExplicitly() {
System.setProperty(CLI_ARGS, "--db=mssql" + ARG_SEPARATOR + "--db-url=jdbc:sqlserver://localhost/keycloak");
System.setProperty("kc.db.driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
System.setProperty("kc.db.tx-type", "enabled");
System.setProperty("kc.db-driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
System.setProperty("kc.db-tx-type", "enabled");
assertTrue(System.getProperty(CLI_ARGS, "").contains("mssql"));
SmallRyeConfig config = createConfig();
assertEquals("jdbc:sqlserver://localhost/keycloak", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
@ -378,11 +378,18 @@ public class ConfigurationTest {
assertEquals("enabled", config.getConfigValue("quarkus.datasource.jdbc.transactions").getValue());
}
@Test
public void testResolveMetricsOption() {
System.setProperty(CLI_ARGS, "--metrics-enabled=true");
SmallRyeConfig config = createConfig();
assertEquals("true", config.getConfigValue("quarkus.datasource.metrics.enabled").getValue());
}
@Test
public void testOptionValueWithEqualSign() {
System.setProperty(CLI_ARGS, "--db-password=my_secret=");
SmallRyeConfig config = createConfig();
assertEquals("my_secret=", config.getConfigValue("kc.db.password").getValue());
assertEquals("my_secret=", config.getConfigValue("kc.db-password").getValue());
}
private Config.Scope initConfig(String... scope) {

View file

@ -1,5 +1,5 @@
spi.hostname.default.frontend-url = ${keycloak.frontendUrl:http://filepropdefault.unittest}
%user-profile.spi.hostname.default.frontend-url = http://filepropprofile.unittest
spi-hostname-default-frontend-url = ${keycloak.frontendUrl:http://filepropdefault.unittest}
%user-profile.spi-hostname-default-frontend-url = http://filepropprofile.unittest
# Default Non-Production Grade Datasource
quarkus.datasource.db-kind=h2

View file

@ -204,7 +204,7 @@ public class CLITestExtension extends QuarkusMainTestExtension {
configureDevServices();
setProperty("kc.db", database.alias());
// databases like mssql are very strict about password policy
setProperty("kc.db.password", "Password1!");
setProperty("kc.db-password", "Password1!");
}
}

View file

@ -45,20 +45,15 @@ public class ShowConfigCommandTest {
.contains("Runtime Configuration"));
Assertions.assertTrue(result.getOutput()
.contains("Quarkus Configuration"));
Assertions.assertTrue(result.getOutput()
.contains("Profile \"import_export\" Configuration"));
}
@Test
@Launch({ CONFIG_FILE_LONG_NAME+"=src/test/resources/ShowConfigCommandTest/keycloak.properties", ShowConfig.NAME, "all" })
@Launch({ CONFIG_FILE_LONG_NAME+"=src/test/resources/ShowConfigCommandTest/keycloak.conf", ShowConfig.NAME, "all" })
void testShowConfigCommandHidesCredentialsInProfiles(LaunchResult result) {
String output = result.getOutput();
Assertions.assertFalse(output.contains("testpw1"));
Assertions.assertFalse(output.contains("testpw2"));
Assertions.assertFalse(output.contains("testpw3"));
Assertions.assertTrue(output.contains("kc.db.password = " + PropertyMappers.VALUE_MASK));
Assertions.assertTrue(output.contains("%dev.kc.db.password = " + PropertyMappers.VALUE_MASK));
Assertions.assertTrue(output.contains("%dev.kc.https.key-store.password = " + PropertyMappers.VALUE_MASK));
Assertions.assertTrue(output.contains("%import_export.kc.db.password = " + PropertyMappers.VALUE_MASK));
Assertions.assertTrue(output.contains("kc.db-password = " + PropertyMappers.VALUE_MASK));
}
}

View file

@ -36,7 +36,7 @@ public class MSSQLStartDatabaseTest extends AbstractStartDabataseTest {
*/
@Override
@Test
@Launch({ "-Dkc.db.tx-type=enabled", "-Dkc.db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver", "start-dev" })
@Launch({ "-Dkc.db-tx-type=enabled", "-Dkc.db-driver=com.microsoft.sqlserver.jdbc.SQLServerDriver", "start-dev" })
void testSuccessful(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertStartedDevMode();

View file

@ -28,21 +28,21 @@ import io.quarkus.test.junit.main.LaunchResult;
public class CustomTransactionDistTest {
@Test
@Launch({ "-Dkc.db.tx-type=enabled", "-Dkc.db.driver=org.postgresql.xa.PGXADataSource", "build", "--db=postgres" })
@Launch({ "-Dkc.db-tx-type=enabled", "-Dkc.db-driver=org.postgresql.xa.PGXADataSource", "build", "--db=postgres" })
void failNoXAUsingXADriver(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("Driver org.postgresql.xa.PGXADataSource is an XA datasource, but XA transactions have not been enabled on the default datasource");
}
@Test
@Launch({ "-Dkc.db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver", "build", "--db=mssql" })
@Launch({ "-Dkc.db-driver=com.microsoft.sqlserver.jdbc.SQLServerDriver", "build", "--db=mssql" })
void failXAUsingNonXADriver(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("Driver is not an XA dataSource, while XA has been enabled in the configuration of the default datasource");
}
@Test
@Launch({ "-Dkc.db.tx-type=enabled", "-Dkc.db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver", "build", "--db=mssql" })
@Launch({ "-Dkc.db-tx-type=enabled", "-Dkc.db-driver=com.microsoft.sqlserver.jdbc.SQLServerDriver", "build", "--db=mssql" })
void testNoXa(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertBuild();

View file

@ -0,0 +1,7 @@
# Default and non-production grade database vendor
db=h2-file
db-username = sa
db-password = keycloak
db-password=testpw1
https-key-store-password=testpw2

View file

@ -1,48 +0,0 @@
# Default and non-production grade database vendor
db=h2-file
db.username = sa
db.password = keycloak
# Insecure requests are disabled by default
http.enabled=false
# Metrics and healthcheck are disabled by default
metrics.enabled=false
# Basic settings for running in production. Change accordingly before deploying the server.
# Database
#%prod.db=postgres
#%prod.db.username=keycloak
#%prod.db.password=password
#%prod.db.url=jdbc:postgresql://localhost/keycloak
# Observability
#%prod.metrics.enabled=true
# HTTP
#%prod.spi.hostname.frontend-url=https://localhost:8443
#%prod.https.certificate.file=${kc.home.dir}conf/server.crt.pem
#%prod.https.certificate.key-file=${kc.home.dir}conf/server.key.pem
#%prod.proxy=reencrypt
#%prod.hostname=myhostname
# Default, and insecure, and non-production grade configuration for the development profile
%dev.http.enabled=true
%dev.hostname.strict=false
%dev.db.password=testpw1
%dev.hostname.strict-https=false
%dev.cluster=local
%dev.spi.theme.cache-themes=false
%dev.spi.theme.cache-templates=false
%dev.spi.theme.static-max-age=-1
%dev.https.key-store.password=testpw2
# The default configuration when running in import or export mode
%import_export.http.enabled=true
%import_export.db.password=testpw3
%import_export.hostname.strict=false
%import_export.hostname.strict-https=false
%import_export.cluster=local
# Logging configuration. INFO is the default level for most of the categories
#quarkus.log.level = DEBUG
quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level=WARN
quarkus.log.category."org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup".level=WARN

View file

@ -14,7 +14,7 @@ Options:
-cf, --config-file <file>
Set the path to a configuration file. By default, configuration properties are
read from the "keycloak.properties" file in the "conf" directory.
read from the "keycloak.conf" file in the "conf" directory.
-D<key>=<value> <sysProps>
Set a Java system property
-h, --help This help message.

View file

@ -14,7 +14,7 @@ Options:
-cf, --config-file <file>
Set the path to a configuration file. By default, configuration properties are
read from the "keycloak.properties" file in the "conf" directory.
read from the "keycloak.conf" file in the "conf" directory.
-D<key>=<value> <sysProps>
Set a Java system property
-h, --help This help message.

View file

@ -14,7 +14,7 @@ Options:
-cf, --config-file <file>
Set the path to a configuration file. By default, configuration properties are
read from the "keycloak.properties" file in the "conf" directory.
read from the "keycloak.conf" file in the "conf" directory.
-D<key>=<value> <sysProps>
Set a Java system property
-h, --help This help message.

View file

@ -713,7 +713,7 @@ Alternatively, you can perform both steps using the following command:
Right now, tests are using a H2 database.
To run tests using a different database such as PostgreSQL, add the following properties into the `testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/keycloak.properties` configuration file:
To run tests using a different database such as PostgreSQL, add the following properties into the `testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/keycloak.conf` configuration file:
```
# HA using PostgreSQL

View file

@ -0,0 +1,48 @@
# H2
db=h2-file
db-username = sa
db-password = keycloak
# Testsuite still relies on HTTP listener
http-enabled=true
# Disables strict hostname
hostname-strict=false
hostname-strict-https=false
# SSL
https-key-store-file=${kc.home.dir}/conf/keycloak.jks
https-key-store-password=secret
https-trust-store-file=${kc.home.dir}/conf/keycloak.truststore
https-trust-store-password=secret
https-client-auth=REQUEST
# Proxy
proxy=passthrough
# Hostname Provider
spi-hostname-default-frontend-url = ${keycloak.frontendUrl:}
# Truststore Provider
spi-truststore-file-file=${kc.home.dir}/conf/keycloak.truststore
spi-truststore-file-password=secret
# Declarative User Profile
spi-user-profile-provider=declarative-user-profile
spi-user-profile-declarative-user-profile-read-only-attributes=deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing
spi-user-profile-declarative-user-profile-admin-read-only-attributes=deniedSomeAdmin
#password-blacklists path
spi-password-policy-password-blacklist-blacklists-path=${kc.home.dir:}/dependency/password-blacklists
# http client connection reuse settings
spi-connections-http-client-default-reuse-connections=false
# set max-length of event representation stored so the db can handle it
spi-events-store-jpa-max-detail-length=2000
# set known protocol ports for basicsamltest
spi-login-protocol-saml-known-protocols=http=8180,https=8543
# File-Based Vault
vault-file-path=${kc.home.dir}secrets

View file

@ -1,48 +0,0 @@
# H2
db=h2-file
db.username = sa
db.password = keycloak
# Testsuite still relies on HTTP listener
http.enabled=true
# Disables strict hostname
hostname.strict=false
hostname.strict-https=false
# SSL
https.key-store.file=${kc.home.dir}/conf/keycloak.jks
https.key-store.password=secret
https.trust-store.file=${kc.home.dir}/conf/keycloak.truststore
https.trust-store.password=secret
https.client-auth=REQUEST
# Proxy
proxy=passthrough
# Hostname Provider
spi.hostname.default.frontend-url = ${keycloak.frontendUrl:}
# Truststore Provider
spi.truststore.file.file=${kc.home.dir}/conf/keycloak.truststore
spi.truststore.file.password=secret
# Declarative User Profile
spi.user-profile.provider=declarative-user-profile
spi.user-profile.declarative-user-profile.read-only-attributes=deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing
spi.user-profile.declarative-user-profile.admin-read-only-attributes=deniedSomeAdmin
#password-blacklists path
spi.password-policy.password-blacklist.blacklists-path=${kc.home.dir:}/dependency/password-blacklists
# http client connection reuse settings
spi.connections-http-client.default.reuse-connections=false
# set max-length of event representation stored so the db can handle it
spi.events-store.jpa.max-detail-length=2000
# set known protocol ports for basicsamltest
spi.login-protocol.saml.known-protocols=http=8180,https=8543
# File-Based Vault
vault.file.path=${kc.home.dir}secrets