[KEYCLOAK-19798] - Less verbose HTTP options and minor changes to property mappers

This commit is contained in:
Pedro Igor 2021-11-11 12:16:14 -03:00
parent 2f9a5aae0f
commit 37b36decbb
8 changed files with 68 additions and 16 deletions

View file

@ -17,6 +17,7 @@
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;
@ -509,6 +510,6 @@ public final class Picocli {
}
public static String normalizeKey(String key) {
return key.replace('-', '.');
return replaceNonAlphanumericByUnderscores(key).replace('_', '.');
}
}

View file

@ -53,6 +53,8 @@ import picocli.CommandLine.Command;
+ " $ ${PARENT-COMMAND-FULL-NAME:-$PARENTCOMMAND} ${COMMAND-NAME} --features=preview%n%n"
+ " Enable metrics:%n%n"
+ " $ ${PARENT-COMMAND-FULL-NAME:-$PARENTCOMMAND} ${COMMAND-NAME} --metrics-enabled=true%n%n"
+ " Change the relative path:%n%n"
+ " $ ${PARENT-COMMAND-FULL-NAME:-$PARENTCOMMAND} ${COMMAND-NAME} --http-relative-path=/auth%n%n"
+ "You can also use the \"--auto-build\" option when starting the server to avoid running this command every time you change a configuration:%n%n"
+ " $ ${PARENT-COMMAND-FULL-NAME:-$PARENTCOMMAND} start --auto-build <OPTIONS>%n%n"
+ "By doing that you have an additional overhead when the server is starting.",

View file

@ -32,6 +32,8 @@ import org.jboss.logging.Logger;
import io.smallrye.config.PropertiesConfigSource;
import org.keycloak.quarkus.runtime.Environment;
import org.keycloak.quarkus.runtime.cli.Picocli;
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
/**
* <p>A configuration source for mapping configuration arguments to their corresponding properties so that they can be recognized
@ -100,7 +102,17 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
log.tracef("Adding property [%s=%s] from command-line", key, value);
properties.put(key, value);
properties.put(getMappedPropertyName(key), value);
String mappedPropertyName = getMappedPropertyName(key);
properties.put(mappedPropertyName, value);
PropertyMapper mapper = PropertyMappers.getMapper(mappedPropertyName);
if (mapper != null) {
properties.put(mapper.getFrom(), value);
}
// to make lookup easier, we normalize the key
properties.put(Picocli.normalizeKey(key), value);
}

View file

@ -39,7 +39,7 @@ public class PropertyMappingInterceptor implements ConfigSourceInterceptor {
public ConfigValue getValue(ConfigSourceInterceptorContext context, String name) {
ConfigValue value = PropertyMappers.getValue(context, name);
if (value == null) {
if (value == null || value.getValue() == null) {
return null;
}

View file

@ -32,6 +32,13 @@ final class HttpPropertyMappers {
.description("The used HTTP Host.")
.paramLabel("host")
.build(),
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")
.to("quarkus.http.port")
.defaultValue(String.valueOf(8080))
@ -71,36 +78,37 @@ final class HttpPropertyMappers {
.description("The file path to a private key in PEM format.")
.paramLabel("file")
.build(),
builder().from("https.certificate.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.certificate.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. If not given, the default (\"password\") is used.")
.description("The password of the key store file.")
.defaultValue("password")
.paramLabel("password")
.isMasked(true)
.build(),
builder().from("https.certificate.key-store-file-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.certificate.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.certificate.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.certificate.trust-store-file-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. " +

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.quarkus.runtime.configuration.mappers;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.BiFunction;
@ -48,7 +49,7 @@ public class PropertyMapper {
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) {
this.from = MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + from;
this.to = to;
this.to = to == null ? this.from : to;
this.defaultValue = defaultValue;
this.mapper = mapper == null ? PropertyMapper::defaultTransformer : mapper;
this.mapFrom = mapFrom;
@ -105,6 +106,10 @@ public class PropertyMapper {
// if not defined, return the current value from the property as a default if the property is not explicitly set
if (defaultValue == null
|| (current != null && !current.getConfigSourceName().equalsIgnoreCase("default values"))) {
if (defaultValue == null && mapper != null) {
String value = current == null ? null : current.getValue();
return ConfigValue.builder().withName(to).withValue(mapper.apply(value, context)).build();
}
return current;
}
@ -245,6 +250,11 @@ public class PropertyMapper {
return this;
}
public Builder expectedValues(String... expectedValues) {
this.expectedValues = Arrays.asList(expectedValues);
return this;
}
public Builder isBuildTimeProperty(boolean isBuildTime) {
this.isBuildTimeProperty = isBuildTime;
return this;
@ -260,6 +270,13 @@ public class PropertyMapper {
return this;
}
public Builder type(Class<Boolean> type) {
if (Boolean.class.equals(type)) {
expectedValues(Boolean.TRUE.toString(), Boolean.FALSE.toString());
}
return this;
}
public PropertyMapper build() {
return new PropertyMapper(from, to, defaultValue, mapper, mapFrom, isBuildTimeProperty, description, paramLabel, isMasked, expectedValues, category);
}

View file

@ -63,7 +63,13 @@ public final class PropertyMappers {
}
boolean isBuildTimeProperty = MAPPERS.entrySet().stream()
.anyMatch(entry -> entry.getValue().getFrom().equals(name) && entry.getValue().isBuildTime());
.anyMatch(new Predicate<Map.Entry<String, PropertyMapper>>() {
@Override
public boolean test(Map.Entry<String, PropertyMapper> entry) {
PropertyMapper mapper = entry.getValue();
return (mapper.getFrom().equals(name) || mapper.getTo().equals(name)) && mapper.isBuildTime();
}
});
if (!isBuildTimeProperty) {
Optional<String> prefixedMapper = PropertyMappers.getPrefixedMapper(name);
@ -126,6 +132,12 @@ public final class PropertyMappers {
}
public static PropertyMapper getMapper(String property) {
PropertyMapper mapper = MAPPERS.get(property);
if (mapper != null) {
return mapper;
}
return MAPPERS.values().stream().filter(new Predicate<PropertyMapper>() {
@Override
public boolean test(PropertyMapper propertyMapper) {

View file

@ -7,10 +7,10 @@ db.password = keycloak
http.enabled=true
# SSL
https.certificate.key-store-file=${kc.home.dir}/conf/keycloak.jks
https.certificate.key-store-password=secret
https.certificate.trust-store-file=${kc.home.dir}/conf/keycloak.truststore
https.certificate.trust-store-password=secret
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