KEYCLOAK-19858: Sanitize CLI Log output and show-config output
This commit is contained in:
parent
a5c3b83443
commit
7f734c9e68
3 changed files with 77 additions and 23 deletions
|
@ -25,6 +25,7 @@ import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuiltT
|
|||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isDevMode;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRuntimeProperty;
|
||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.formatValue;
|
||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.isBuildTimeProperty;
|
||||
import static org.keycloak.utils.StringUtil.isNotBlank;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIST;
|
||||
|
@ -34,6 +35,7 @@ import java.io.FileInputStream;
|
|||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -49,13 +51,13 @@ import org.keycloak.quarkus.runtime.cli.command.Main;
|
|||
import org.keycloak.quarkus.runtime.cli.command.Start;
|
||||
import org.keycloak.quarkus.runtime.cli.command.StartDev;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.ConfigCategory;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
|
||||
import io.quarkus.runtime.Quarkus;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Model.CommandSpec;
|
||||
|
@ -118,11 +120,12 @@ public final class Picocli {
|
|||
if (hasConfigChanges()) {
|
||||
cmd.getOut().println("Changes detected in configuration. Updating the server image.");
|
||||
if(!isDevMode()) {
|
||||
List<String> cliInput = getSanitizedCliInput();
|
||||
cmd.getOut().printf("For an optional runtime and bypass this step, please run the '%s' command prior to starting the server:%n%n\t%s %s %s%n",
|
||||
Build.NAME,
|
||||
Environment.getCommand(),
|
||||
Build.NAME,
|
||||
String.join(" ", asList(ARG_SPLIT.split(Environment.getConfigArgs()))) + "\n");
|
||||
String.join(" ", cliInput) + "\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -130,6 +133,39 @@ public final class Picocli {
|
|||
return hasProviderChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the raw cli input for possible credentials / properties which should be masked,
|
||||
* and masks them.
|
||||
* @return a list of potentially masked properties in CLI format, e.g. `--db-password=*******`
|
||||
* instead of the actual passwords value.
|
||||
*/
|
||||
private static List<String> getSanitizedCliInput() {
|
||||
|
||||
if(Environment.getConfigArgs().isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<String> rawCliArgs = asList(ARG_SPLIT.split(Environment.getConfigArgs()));
|
||||
List<String> properties = new ArrayList<>();
|
||||
|
||||
if (!rawCliArgs.isEmpty()) {
|
||||
for(String rawCliArg : rawCliArgs) {
|
||||
String rawKey = rawCliArg.split("=")[0];
|
||||
PropertyMapper mapper = PropertyMappers.getMapper(rawKey);
|
||||
String value = rawCliArg.split("=")[1];
|
||||
|
||||
if (mapper != null) {
|
||||
value = formatValue(
|
||||
mapper.getFrom(),
|
||||
value);
|
||||
}
|
||||
|
||||
properties.add(rawKey + "=" + value);
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private static void runReAugmentation(List<String> cliArgs, CommandLine cmd) {
|
||||
List<String> configArgsList = new ArrayList<>(cliArgs);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ 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 {
|
||||
|
@ -46,6 +47,8 @@ public class PropertyMapper {
|
|||
private final ConfigCategory category;
|
||||
private final String paramLabel;
|
||||
private final boolean hidden;
|
||||
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,
|
||||
|
@ -62,6 +65,7 @@ public class PropertyMapper {
|
|||
this.expectedValues = expectedValues == null ? Collections.emptyList() : expectedValues;
|
||||
this.category = category != null ? category : ConfigCategory.GENERAL;
|
||||
this.hidden = hidden;
|
||||
setCliFormat(this.from);
|
||||
}
|
||||
|
||||
public static PropertyMapper.Builder builder(String fromProp, String toProp) {
|
||||
|
@ -163,6 +167,26 @@ public class PropertyMapper {
|
|||
return hidden;
|
||||
}
|
||||
|
||||
public boolean isBuildTime() {
|
||||
return buildTime;
|
||||
}
|
||||
|
||||
public String getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public String getParamLabel() {
|
||||
return paramLabel;
|
||||
}
|
||||
|
||||
public String getCliFormat() {
|
||||
return cliFormat;
|
||||
}
|
||||
|
||||
boolean isMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
private ConfigValue transformValue(String value, ConfigSourceInterceptorContext context) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
|
@ -181,20 +205,8 @@ public class PropertyMapper {
|
|||
return null;
|
||||
}
|
||||
|
||||
public boolean isBuildTime() {
|
||||
return buildTime;
|
||||
}
|
||||
|
||||
boolean isMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public String getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public String getParamLabel() {
|
||||
return paramLabel;
|
||||
private void setCliFormat(String from) {
|
||||
cliFormat = Picocli.ARG_PREFIX + PropertyMappers.toCLIFormat(from).substring(3);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
public final class PropertyMappers {
|
||||
|
||||
public static String VALUE_MASK = "*******";
|
||||
static final MappersConfig MAPPERS = new MappersConfig();
|
||||
|
||||
private PropertyMappers(){}
|
||||
|
@ -96,6 +97,7 @@ public final class PropertyMappers {
|
|||
if (name.indexOf('.') == -1) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX
|
||||
.concat(name.substring(3, name.lastIndexOf('.') + 1)
|
||||
.replaceAll("\\.", "-") + name.substring(name.lastIndexOf('.') + 1));
|
||||
|
@ -116,23 +118,26 @@ public final class PropertyMappers {
|
|||
}
|
||||
|
||||
public static String formatValue(String property, String value) {
|
||||
property = removeProfilePrefixIfNeeded(property);
|
||||
PropertyMapper mapper = getMapper(property);
|
||||
|
||||
if (mapper != null && mapper.isMask()) {
|
||||
return "*******";
|
||||
return VALUE_MASK;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static PropertyMapper getMapper(String property) {
|
||||
PropertyMapper mapper = MAPPERS.get(property);
|
||||
|
||||
if (mapper != null) {
|
||||
return mapper;
|
||||
private static String removeProfilePrefixIfNeeded(String property) {
|
||||
if(property.startsWith("%")) {
|
||||
String profilePrefix = property.substring(0, property.indexOf(".") +1);
|
||||
property = property.split(profilePrefix)[1];
|
||||
}
|
||||
return property;
|
||||
}
|
||||
|
||||
return null;
|
||||
public static PropertyMapper getMapper(String property) {
|
||||
return MAPPERS.get(property);
|
||||
}
|
||||
|
||||
public static Collection<PropertyMapper> getMappers() {
|
||||
|
@ -164,6 +169,7 @@ public final class PropertyMappers {
|
|||
for (PropertyMapper mapper : mappers) {
|
||||
super.put(mapper.getTo(), mapper);
|
||||
super.put(mapper.getFrom(), mapper);
|
||||
super.put(mapper.getCliFormat(), mapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue