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) @Record(ExecutionTime.RUNTIME_INIT)
@BuildStep @BuildStep
void configureInfinispan(KeycloakRecorder recorder, BuildProducer<SyntheticBeanBuildItem> syntheticBeanBuildItems, ShutdownContextBuildItem shutdownContext) { 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) { if (configFile != null) {
Path configPath = Paths.get(configFile); Path configPath = Paths.get(configFile);

View file

@ -414,7 +414,7 @@ class KeycloakProcessor {
@BuildStep(onlyIf = IsDevelopment.class) @BuildStep(onlyIf = IsDevelopment.class)
void configureDevMode(BuildProducer<HotDeploymentWatchedFileBuildItem> hotFiles) { 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( private Map<Spi, Map<Class<? extends Provider>, Map<String, ProviderFactory>>> loadFactories(
@ -591,6 +591,6 @@ class KeycloakProcessor {
} }
private boolean isMetricsEnabled() { 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 @RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest() static final QuarkusUnitTest test = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource("keycloak.properties", "META-INF/keycloak.properties")); .addAsResource("keycloak.conf", "META-INF/keycloak.conf"));
@Test @Test
public void testReadinessDown() { public void testReadinessDown() {

View file

@ -33,7 +33,7 @@ public class KeycloakReadyHealthCheckTest {
@RegisterExtension @RegisterExtension
static final QuarkusUnitTest test = new QuarkusUnitTest() static final QuarkusUnitTest test = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addAsResource("keycloak.properties", "META-INF/keycloak.properties")); .addAsResource("keycloak.conf", "META-INF/keycloak.conf"));
@Test @Test
public void testLivenessUp() { 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) { private void printErrorHints(PrintWriter errorWriter, Throwable cause) {
if (cause instanceof FileSystemException) { if (cause instanceof FileSystemException) {
FileSystemException fse = (FileSystemException) cause; 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))) { if (fse.getFile().equals(Optional.ofNullable(httpsCertFile.getValue()).orElse(null))) {
logError(errorWriter, Messages.httpsConfigurationNotSet().getMessage()); logError(errorWriter, Messages.httpsConfigurationNotSet().getMessage());

View file

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

View file

@ -107,7 +107,7 @@ public final class Main {
@Option(names = { CONFIG_FILE_SHORT_NAME, CONFIG_FILE_LONG_NAME }, @Option(names = { CONFIG_FILE_SHORT_NAME, CONFIG_FILE_LONG_NAME },
arity = "1", 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") paramLabel = "file")
public void setConfigFile(String path) { public void setConfigFile(String path) {
System.setProperty(KeycloakPropertiesConfigSource.KEYCLOAK_CONFIG_FILE_PROP, 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.Environment.getCurrentOrPersistedProfile;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfigValue; 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.Configuration.getPropertyNames;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.canonicalFormat;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.formatValue; import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.formatValue;
import java.util.HashSet; import java.util.HashSet;
@ -63,8 +62,6 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
printRunTimeConfig(properties, profile); printRunTimeConfig(properties, profile);
if (configArgs.equalsIgnoreCase("all")) { if (configArgs.equalsIgnoreCase("all")) {
printAllProfilesConfig(properties, profile);
spec.commandLine().getOut().println("Quarkus Configuration:"); spec.commandLine().getOut().println("Quarkus Configuration:");
properties.get(MicroProfileConfigProvider.NS_QUARKUS).stream().sorted() properties.get(MicroProfileConfigProvider.NS_QUARKUS).stream().sorted()
.forEachOrdered(this::printProperty); .forEachOrdered(this::printProperty);
@ -84,37 +81,10 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
spec.commandLine().getOut().println("Runtime Configuration:"); spec.commandLine().getOut().println("Runtime Configuration:");
properties.get(MicroProfileConfigProvider.NS_KEYCLOAK).stream().sorted() properties.get(MicroProfileConfigProvider.NS_KEYCLOAK).stream().sorted()
.filter(name -> { .filter(uniqueNames::add)
String canonicalFormat = canonicalFormat(name);
if (!canonicalFormat.equals(name)) {
return uniqueNames.add(canonicalFormat);
}
return uniqueNames.add(name);
})
.forEachOrdered(this::printProperty); .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() { private static Map<String, Set<String>> getPropertiesByGroup() {
Map<String, Set<String>> properties = StreamSupport Map<String, Set<String>> properties = StreamSupport
.stream(getPropertyNames().spliterator(), false) .stream(getPropertyNames().spliterator(), false)
@ -147,8 +117,7 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
} }
private void printProperty(String property) { private void printProperty(String property) {
String canonicalFormat = canonicalFormat(property); ConfigValue configValue = getConfigValue(property);
ConfigValue configValue = getConfigValue(canonicalFormat);
if (configValue.getValue() == null) { if (configValue.getValue() == null) {
configValue = getConfigValue(property); 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.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_LONG;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_SHORT; 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.Configuration.getMappedPropertyName;
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX; import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
@ -97,7 +99,7 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
return value; return value;
} }
return properties.get(propertyName.replace('-', '.')); return properties.get(propertyName.replace(OPTION_PART_SEPARATOR_CHAR, '.'));
} }
private static Map<String, String> parseArgument() { private static Map<String, String> parseArgument() {
@ -127,9 +129,6 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
if (mapper != null) { if (mapper != null) {
properties.put(mapper.getFrom(), value); 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; 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.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.Optional;
import java.util.function.Function; import java.util.function.Function;
import io.smallrye.config.ConfigValue; import io.smallrye.config.ConfigValue;
import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigProviderResolver;
import org.eclipse.microprofile.config.spi.ConfigProviderResolver; import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.eclipse.microprofile.config.spi.ConfigSource; import org.eclipse.microprofile.config.spi.ConfigSource;
@ -40,6 +38,9 @@ import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
*/ */
public final class Configuration { 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() { private Configuration() {
} }
@ -98,19 +99,16 @@ public final class Configuration {
} }
public static String getMappedPropertyName(String key) { public static String getMappedPropertyName(String key) {
for (PropertyMapper mapper : PropertyMappers.getMappers()) { PropertyMapper mapper = PropertyMappers.getMapper(key);
String mappedProperty = mapper.getFrom();
List<String> expectedFormats = Arrays.asList(mappedProperty, toCLIFormat(mappedProperty), mappedProperty.toUpperCase().replace('.', '_').replace('-', '_'));
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) { public static Optional<String> getRuntimeProperty(String name) {
for (ConfigSource configSource : getConfig().getConfigSources()) { for (ConfigSource configSource : getConfig().getConfigSources()) {
if (PersistedConfigSource.NAME.equals(configSource.getName())) { if (PersistedConfigSource.NAME.equals(configSource.getName())) {
@ -131,6 +129,14 @@ public final class Configuration {
return Optional.empty(); 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) { private static String getValue(ConfigSource configSource, String name) {
String value = configSource.getValue(name); String value = configSource.getValue(name);

View file

@ -33,10 +33,12 @@ public class KcEnvConfigSource extends EnvConfigSource {
private static Map<String, String> buildProperties() { private static Map<String, String> buildProperties() {
Map<String, String> properties = new HashMap<>(); Map<String, String> properties = new HashMap<>();
String kcPrefix = replaceNonAlphanumericByUnderscores(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.toUpperCase());
for (Map.Entry<String, String> entry : System.getenv().entrySet()) { for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
if (key.startsWith(replaceNonAlphanumericByUnderscores(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.toUpperCase()))) {
if (key.startsWith(kcPrefix)) {
properties.put(getMappedPropertyName(key), entry.getValue()); 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 ConfigArgsConfigSource());
CONFIG_SOURCES.add(new SysPropConfigSource());
CONFIG_SOURCES.add(new KcEnvConfigSource()); CONFIG_SOURCES.add(new KcEnvConfigSource());
CONFIG_SOURCES.add(PersistedConfigSource.getInstance()); CONFIG_SOURCES.add(PersistedConfigSource.getInstance());

View file

@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.microprofile.config.spi.ConfigSource; 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; 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 { public class KeycloakPropertiesConfigSource extends AbstractLocationConfigSourceLoader {
private static final Pattern DOT_SPLIT = Pattern.compile("\\."); private static final Pattern DOT_SPLIT = Pattern.compile("\\.");
private static final String KEYCLOAK_CONFIG_FILE_ENV = "KC_CONFIG_FILE"; 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"; public static final String KEYCLOAK_CONFIG_FILE_PROP = NS_KEYCLOAK_PREFIX + "config.file";
@Override @Override
protected String[] getFileExtensions() { protected String[] getFileExtensions() {
return new String[] { "properties" }; return new String[] { "conf" };
} }
@Override @Override
protected ConfigSource loadConfigSource(URL url, int ordinal) throws IOException { 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 { public static class InClassPath extends KeycloakPropertiesConfigSource implements ConfigSourceProvider {
@Override @Override
public List<ConfigSource> getConfigSources(final ClassLoader classLoader) { 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 @Override
@ -122,7 +123,7 @@ public class KeycloakPropertiesConfigSource extends AbstractLocationConfigSource
String homeDir = Environment.getHomeDir(); String homeDir = Environment.getHomeDir();
if (homeDir != null) { 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()) { if (file.exists()) {
filePath = file.getAbsolutePath(); filePath = file.getAbsolutePath();

View file

@ -17,6 +17,9 @@
package org.keycloak.quarkus.runtime.configuration; 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.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -60,7 +63,7 @@ public class MicroProfileConfigProvider implements Config.ConfigProvider {
public MicroProfileScope(String... scope) { public MicroProfileScope(String... scope) {
this.scope = 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 @Override
@ -119,14 +122,14 @@ public class MicroProfileConfigProvider implements Config.ConfigProvider {
.filter(new Predicate<String>() { .filter(new Predicate<String>() {
@Override @Override
public boolean test(String key) { 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()); .collect(Collectors.toSet());
} }
private <T> T getValue(String key, Class<T> clazz, T defaultValue) { 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 value;
} }
return super.getValue(propertyName.replace('-', '.')); return super.getValue(propertyName.replace(Configuration.OPTION_PART_SEPARATOR_CHAR, '.'));
} }
private static Map<String, String> readProperties() { 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") .expectedValues("local", "ispn")
.build(), .build(),
builder().from("cache-stack") 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 " .description("Define the default stack to use for cluster communication and node discovery. This option only takes effect "
+ "if 'cache' is set to 'ispn'.") + "if 'cache' is set to 'ispn'.")
.defaultValue("udp") .defaultValue("udp")
@ -32,9 +32,9 @@ final class ClusteringPropertyMappers {
.isBuildTimeProperty(true) .isBuildTimeProperty(true)
.expectedValues(Arrays.asList("tcp", "udp", "kubernetes", "ec2", "azure", "google")) .expectedValues(Arrays.asList("tcp", "udp", "kubernetes", "ec2", "azure", "google"))
.build(), .build(),
builder().from("cache.config-file") builder().from("cache-config-file")
.mapFrom("cache") .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.") .description("Defines the file from which cache configuration should be loaded from.")
.transformer(new BiFunction<String, ConfigSourceInterceptorContext, String>() { .transformer(new BiFunction<String, ConfigSourceInterceptorContext, String>() {
@Override @Override

View file

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

View file

@ -8,35 +8,35 @@ final class HostnamePropertyMappers {
public static PropertyMapper[] getHostnamePropertyMappers() { public static PropertyMapper[] getHostnamePropertyMappers() {
return new PropertyMapper[] { return new PropertyMapper[] {
builder().from("hostname") builder().from("hostname")
.to("kc.spi.hostname.default.hostname") .to("kc.spi-hostname-default-hostname")
.description("Hostname for the Keycloak server.") .description("Hostname for the Keycloak server.")
.paramLabel("hostname") .paramLabel("hostname")
.build(), .build(),
builder().from("hostname.admin") builder().from("hostname-admin")
.to("kc.spi.hostname.default.admin") .to("kc.spi-hostname-default-admin")
.description("Overrides the hostname for the admin console and APIs.") .description("Overrides the hostname for the admin console and APIs.")
.paramLabel("url") .paramLabel("url")
.build(), .build(),
builder().from("hostname.strict") builder().from("hostname-strict")
.to("kc.spi.hostname.default.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.") .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) .type(Boolean.class)
.defaultValue(Boolean.TRUE.toString()) .defaultValue(Boolean.TRUE.toString())
.build(), .build(),
builder().from("hostname.strict-https") builder().from("hostname-strict-https")
.to("kc.spi.hostname.default.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.") .description("Forces URLs to use HTTPS. Only needed if proxy does not properly set the X-Forwarded-Proto header.")
.hidden(true) .hidden(true)
.defaultValue(Boolean.TRUE.toString()) .defaultValue(Boolean.TRUE.toString())
.type(Boolean.class) .type(Boolean.class)
.build(), .build(),
builder().from("hostname.strict-backchannel") builder().from("hostname-strict-backchannel")
.to("kc.spi.hostname.default.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.") .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) .type(Boolean.class)
.build(), .build(),
builder().from("hostname.path") builder().from("hostname-path")
.to("kc.spi.hostname.default.path") .to("kc.spi-hostname-default-path")
.description("This should be set if proxy uses a different context-path for Keycloak.") .description("This should be set if proxy uses a different context-path for Keycloak.")
.paramLabel("path") .paramLabel("path")
.build() .build()

View file

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

View file

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

View file

@ -16,13 +16,18 @@
*/ */
package org.keycloak.quarkus.runtime.configuration.mappers; 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.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import io.smallrye.config.ConfigSourceInterceptorContext; import io.smallrye.config.ConfigSourceInterceptorContext;
import io.smallrye.config.ConfigValue; import io.smallrye.config.ConfigValue;
import org.keycloak.quarkus.runtime.cli.Picocli;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider; import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
public class PropertyMapper { public class PropertyMapper {
@ -47,9 +52,9 @@ public class PropertyMapper {
private final ConfigCategory category; private final ConfigCategory category;
private final String paramLabel; private final String paramLabel;
private final boolean hidden; private final boolean hidden;
private final String envVarFormat;
private String cliFormat; private String cliFormat;
PropertyMapper(String from, String to, String defaultValue, BiFunction<String, ConfigSourceInterceptorContext, String> mapper, 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, String mapFrom, boolean buildTime, String description, String paramLabel, boolean mask, Iterable<String> expectedValues,
ConfigCategory category, boolean hidden) { ConfigCategory category, boolean hidden) {
@ -65,7 +70,8 @@ public class PropertyMapper {
this.expectedValues = expectedValues == null ? Collections.emptyList() : expectedValues; this.expectedValues = expectedValues == null ? Collections.emptyList() : expectedValues;
this.category = category != null ? category : ConfigCategory.GENERAL; this.category = category != null ? category : ConfigCategory.GENERAL;
this.hidden = hidden; this.hidden = hidden;
setCliFormat(this.from); this.cliFormat = toCliFormat(from);
this.envVarFormat = toEnvVarFormat(this.from);
} }
public static PropertyMapper.Builder builder(String fromProp, String toProp) { public static PropertyMapper.Builder builder(String fromProp, String toProp) {
@ -87,9 +93,9 @@ public class PropertyMapper {
ConfigValue getConfigValue(String name, ConfigSourceInterceptorContext context) { ConfigValue getConfigValue(String name, ConfigSourceInterceptorContext context) {
String from = this.from; 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 // 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 // try to obtain the value for the property we want to map first
@ -98,7 +104,7 @@ public class PropertyMapper {
if (config == null) { if (config == null) {
if (mapFrom != 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 // 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); ConfigValue parentValue = context.proceed(parentKey);
if (parentValue == null) { if (parentValue == null) {
@ -187,6 +193,10 @@ public class PropertyMapper {
return cliFormat; return cliFormat;
} }
public String getEnvVarFormat() {
return envVarFormat;
}
boolean isMask() { boolean isMask() {
return mask; return mask;
} }
@ -209,10 +219,6 @@ public class PropertyMapper {
return null; return null;
} }
private void setCliFormat(String from) {
cliFormat = Picocli.ARG_PREFIX + PropertyMappers.toCLIFormat(from).substring(3);
}
public static class Builder { public static class Builder {
private String from; private String from;

View file

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

View file

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

View file

@ -210,7 +210,7 @@ public final class DefaultHostnameProvider implements HostnameProvider, Hostname
defaultPath = config.get("path"); defaultPath = config.get("path");
noProxy = Configuration.getConfigValue("kc.proxy").getValue().equals("none"); 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"); adminHostName = config.get("admin");
strictBackChannel = config.getBoolean("strict-backchannel", false); strictBackChannel = config.getBoolean("strict-backchannel", false);

View file

@ -100,11 +100,11 @@ public final class Database {
@Override @Override
public String apply(String alias) { public String apply(String alias) {
if ("h2-file".equalsIgnoreCase(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 + 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"), asList("liquibase.database.core.H2Database"),
@ -114,13 +114,13 @@ public final class Database {
"com.mysql.cj.jdbc.MysqlXADataSource", "com.mysql.cj.jdbc.MysqlXADataSource",
"org.hibernate.dialect.MySQL8Dialect", "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") asList("org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase")
), ),
MARIADB("mariadb", MARIADB("mariadb",
"org.mariadb.jdbc.MySQLDataSource", "org.mariadb.jdbc.MySQLDataSource",
"org.hibernate.dialect.MariaDBDialect", "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") asList("org.keycloak.connections.jpa.updater.liquibase.UpdatedMariaDBDatabase")
), ),
POSTGRES("postgresql", POSTGRES("postgresql",
@ -134,7 +134,7 @@ public final class Database {
return "io.quarkus.hibernate.orm.runtime.dialect.QuarkusPostgreSQL10Dialect"; 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", asList("liquibase.database.core.PostgresDatabase",
"org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase"), "org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase"),
"postgres", "postgres-95" "postgres", "postgres-95"
@ -151,14 +151,14 @@ public final class Database {
return "org.hibernate.dialect.SQLServer2016Dialect"; 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"), asList("org.keycloak.quarkus.runtime.storage.database.liquibase.database.CustomMSSQLDatabase"),
"mssql", "mssql-2012" "mssql", "mssql-2012"
), ),
ORACLE("oracle", ORACLE("oracle",
"oracle.jdbc.xa.client.OracleXADataSource", "oracle.jdbc.xa.client.OracleXADataSource",
"org.hibernate.dialect.Oracle12cDialect", "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") asList("liquibase.database.core.OracleDatabase")
); );

View file

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

View file

@ -74,11 +74,11 @@ public class CacheManagerFactory {
private boolean isStartEagerly() { private boolean isStartEagerly() {
// eagerly starts caches by default // 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() { private Integer getStartTimeout() {
return Integer.getInteger("kc.cache.ispn.start-timeout", 120); return Integer.getInteger("kc.cache-ispn-start-timeout", 120);
} }
private void shutdownThreadPool() { private void shutdownThreadPool() {

View file

@ -1,27 +1,27 @@
# Default and non-production grade database vendor # Default and non-production grade database vendor
db=h2-file db=h2-file
db.username = sa db-username = sa
db.password = keycloak db-password = keycloak
# Insecure requests are disabled by default # Insecure requests are disabled by default
http.enabled=false http-enabled=false
# Metrics and healthcheck are disabled by default # 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 # Default, and insecure, and non-production grade configuration for the development profile
%dev.http.enabled=true %dev.http-enabled=true
%dev.hostname.strict=false %dev.hostname-strict=false
%dev.hostname.strict-https=false %dev.hostname-strict-https=false
%dev.cache=local %dev.cache=local
%dev.spi.theme.cache-themes=false %dev.spi-theme-cache-themes=false
%dev.spi.theme.cache-templates=false %dev.spi-theme-cache-templates=false
%dev.spi.theme.static-max-age=-1 %dev.spi-theme-static-max-age=-1
# The default configuration when running in import or export mode # The default configuration when running in import or export mode
%import_export.http.enabled=true %import_export.http-enabled=true
%import_export.hostname.strict=false %import_export.hostname-strict=false
%import_export.hostname.strict-https=false %import_export.hostname-strict-https=false
%import_export.cluster=local %import_export.cluster=local
# Logging configuration. INFO is the default level for most of the categories # 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); Config.Scope config = initConfig("vault", FilesPlainTextVaultProviderFactory.PROVIDER_ID);
assertEquals("/foo/bar", config.get("dir")); assertEquals("/foo/bar", config.get("dir"));
assertTrue(config.getPropertyNames() assertTrue(config.getPropertyNames()
.contains("kc.spi.vault.".concat(FilesPlainTextVaultProviderFactory.PROVIDER_ID).concat(".dir"))); .contains("kc.spi-vault-".concat(FilesPlainTextVaultProviderFactory.PROVIDER_ID).concat("-dir")));
} }
@Test @Test
public void testSysPropPriorityOverEnvVar() { public void testEnvVarPriorityOverSysProps() {
putEnvVar("KC_SPI_HOSTNAME_DEFAULT_FRONTEND_URL", "http://envvar.unittest"); putEnvVar("KC_SPI_HOSTNAME_DEFAULT_FRONTEND_URL", "http://envvar.unittest");
System.setProperty("kc.spi.hostname.default.frontend-url", "http://propvar.unittest"); System.setProperty("kc.spi-hostname-default-frontend-url", "http://propvar.unittest");
assertEquals("http://propvar.unittest", initConfig("hostname", "default").get("frontendUrl")); assertEquals("http://envvar.unittest", initConfig("hostname", "default").get("frontendUrl"));
} }
@Test @Test
@ -203,13 +203,13 @@ public class ConfigurationTest {
assertEquals("secrets", config.get("dir")); assertEquals("secrets", config.get("dir"));
System.getProperties().remove(CLI_ARGS); 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"); config = initConfig("client-registration", "openid-connect");
assertEquals(1, config.getPropertyNames().size()); assertEquals(1, config.getPropertyNames().size());
assertEquals("http://c.jwk.url", config.get("static-jwk-url")); assertEquals("http://c.jwk.url", config.get("static-jwk-url"));
System.getProperties().remove(CLI_ARGS); 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"); putEnvVar("KC_SPI_CLIENT_REGISTRATION_OPENID_CONNECT_STATIC_JWK_URL", "http://c.jwk.url/from-env");
config = initConfig("client-registration", "openid-connect"); config = initConfig("client-registration", "openid-connect");
assertEquals(1, config.getPropertyNames().size()); assertEquals(1, config.getPropertyNames().size());
@ -279,8 +279,8 @@ public class ConfigurationTest {
@Test @Test
public void testDatabaseProperties() { public void testDatabaseProperties() {
System.setProperty("kc.db.url.properties", ";;test=test;test1=test1"); System.setProperty("kc.db-url-properties", ";;test=test;test1=test1");
System.setProperty("kc.db.url.path", "test-dir"); System.setProperty("kc.db-url-path", "test-dir");
System.setProperty(CLI_ARGS, "--db=h2-file"); System.setProperty(CLI_ARGS, "--db=h2-file");
SmallRyeConfig config = createConfig(); SmallRyeConfig config = createConfig();
assertEquals(QuarkusH2Dialect.class.getName(), config.getConfigValue("quarkus.hibernate-orm.dialect").getValue()); 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(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()); 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"); System.setProperty(CLI_ARGS, "--db=mariadb");
config = createConfig(); config = createConfig();
assertEquals("jdbc:mariadb://localhost/keycloak?test=test&test1=test1", config.getConfigValue("quarkus.datasource.jdbc.url").getValue()); 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"); System.setProperty(CLI_ARGS, "--db-schema=test-schema");
config = createConfig(); 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()); assertEquals("test-schema", config.getConfigValue("quarkus.hibernate-orm.database.default-schema").getValue());
} }
@ -368,8 +368,8 @@ public class ConfigurationTest {
@Test @Test
public void testDatabaseDriverSetExplicitly() { public void testDatabaseDriverSetExplicitly() {
System.setProperty(CLI_ARGS, "--db=mssql" + ARG_SEPARATOR + "--db-url=jdbc:sqlserver://localhost/keycloak"); 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-driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
System.setProperty("kc.db.tx-type", "enabled"); System.setProperty("kc.db-tx-type", "enabled");
assertTrue(System.getProperty(CLI_ARGS, "").contains("mssql")); assertTrue(System.getProperty(CLI_ARGS, "").contains("mssql"));
SmallRyeConfig config = createConfig(); SmallRyeConfig config = createConfig();
assertEquals("jdbc:sqlserver://localhost/keycloak", config.getConfigValue("quarkus.datasource.jdbc.url").getValue()); 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()); 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 @Test
public void testOptionValueWithEqualSign() { public void testOptionValueWithEqualSign() {
System.setProperty(CLI_ARGS, "--db-password=my_secret="); System.setProperty(CLI_ARGS, "--db-password=my_secret=");
SmallRyeConfig config = createConfig(); 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) { private Config.Scope initConfig(String... scope) {

View file

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

View file

@ -204,7 +204,7 @@ public class CLITestExtension extends QuarkusMainTestExtension {
configureDevServices(); configureDevServices();
setProperty("kc.db", database.alias()); setProperty("kc.db", database.alias());
// databases like mssql are very strict about password policy // 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")); .contains("Runtime Configuration"));
Assertions.assertTrue(result.getOutput() Assertions.assertTrue(result.getOutput()
.contains("Quarkus Configuration")); .contains("Quarkus Configuration"));
Assertions.assertTrue(result.getOutput()
.contains("Profile \"import_export\" Configuration"));
} }
@Test @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) { void testShowConfigCommandHidesCredentialsInProfiles(LaunchResult result) {
String output = result.getOutput(); String output = result.getOutput();
Assertions.assertFalse(output.contains("testpw1")); Assertions.assertFalse(output.contains("testpw1"));
Assertions.assertFalse(output.contains("testpw2")); Assertions.assertFalse(output.contains("testpw2"));
Assertions.assertFalse(output.contains("testpw3")); Assertions.assertFalse(output.contains("testpw3"));
Assertions.assertTrue(output.contains("kc.db.password = " + PropertyMappers.VALUE_MASK)); 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));
} }
} }

View file

@ -36,7 +36,7 @@ public class MSSQLStartDatabaseTest extends AbstractStartDabataseTest {
*/ */
@Override @Override
@Test @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) { void testSuccessful(LaunchResult result) {
CLIResult cliResult = (CLIResult) result; CLIResult cliResult = (CLIResult) result;
cliResult.assertStartedDevMode(); cliResult.assertStartedDevMode();

View file

@ -28,21 +28,21 @@ import io.quarkus.test.junit.main.LaunchResult;
public class CustomTransactionDistTest { public class CustomTransactionDistTest {
@Test @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) { void failNoXAUsingXADriver(LaunchResult result) {
CLIResult cliResult = (CLIResult) 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"); cliResult.assertError("Driver org.postgresql.xa.PGXADataSource is an XA datasource, but XA transactions have not been enabled on the default datasource");
} }
@Test @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) { void failXAUsingNonXADriver(LaunchResult result) {
CLIResult cliResult = (CLIResult) 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"); cliResult.assertError("Driver is not an XA dataSource, while XA has been enabled in the configuration of the default datasource");
} }
@Test @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) { void testNoXa(LaunchResult result) {
CLIResult cliResult = (CLIResult) result; CLIResult cliResult = (CLIResult) result;
cliResult.assertBuild(); 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> -cf, --config-file <file>
Set the path to a configuration file. By default, configuration properties are 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> -D<key>=<value> <sysProps>
Set a Java system property Set a Java system property
-h, --help This help message. -h, --help This help message.

View file

@ -14,7 +14,7 @@ Options:
-cf, --config-file <file> -cf, --config-file <file>
Set the path to a configuration file. By default, configuration properties are 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> -D<key>=<value> <sysProps>
Set a Java system property Set a Java system property
-h, --help This help message. -h, --help This help message.

View file

@ -14,7 +14,7 @@ Options:
-cf, --config-file <file> -cf, --config-file <file>
Set the path to a configuration file. By default, configuration properties are 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> -D<key>=<value> <sysProps>
Set a Java system property Set a Java system property
-h, --help This help message. -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. 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 # 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