Enhance masking around config-keystore (#30348)
Closes #30346 Signed-off-by: Václav Muzikář <vmuzikar@redhat.com>
This commit is contained in:
parent
e6df8a2866
commit
375ea9da03
8 changed files with 40 additions and 12 deletions
|
@ -124,7 +124,7 @@ After executing the command, you will be prompted to *Enter the password to be s
|
||||||
|
|
||||||
When the KeyStore is created, you can start the server using the following parameters:
|
When the KeyStore is created, you can start the server using the following parameters:
|
||||||
|
|
||||||
<@kc.start parameters="--config-keystore=/path/to/keystore.p12 --config-keystore-password=storepass --config-keystore-type=PKCS12"/>
|
<@kc.start parameters="--config-keystore=/path/to/keystore.p12 --config-keystore-password=keystorepass --config-keystore-type=PKCS12"/>
|
||||||
|
|
||||||
=== Format for raw Quarkus properties
|
=== Format for raw Quarkus properties
|
||||||
In most cases, the available configuration options should suffice to configure the server.
|
In most cases, the available configuration options should suffice to configure the server.
|
||||||
|
|
|
@ -34,7 +34,7 @@ import static org.keycloak.quarkus.runtime.configuration.Configuration.getCurren
|
||||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRawPersistedProperty;
|
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRawPersistedProperty;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRuntimeProperty;
|
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRuntimeProperty;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
|
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.formatValue;
|
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.maskValue;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.isBuildTimeProperty;
|
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.isBuildTimeProperty;
|
||||||
import static org.keycloak.utils.StringUtil.isNotBlank;
|
import static org.keycloak.utils.StringUtil.isNotBlank;
|
||||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIST;
|
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIST;
|
||||||
|
@ -222,7 +222,7 @@ public final class Picocli {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.add(key + "=" + formatValue(key, value));
|
properties.add(key + "=" + maskValue(key, value));
|
||||||
}
|
}
|
||||||
}, arg -> {
|
}, arg -> {
|
||||||
properties.add(arg);
|
properties.add(arg);
|
||||||
|
|
|
@ -22,7 +22,7 @@ import static org.keycloak.quarkus.runtime.Environment.setProfile;
|
||||||
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.Configuration.getRuntimeProperty;
|
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.maskValue;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -148,7 +148,9 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
|
||||||
value = getRuntimeProperty(property).orElse(value);
|
value = getRuntimeProperty(property).orElse(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
spec.commandLine().getOut().printf("\t%s = %s (%s)%n", configValue.getName(), formatValue(configValue.getName(), value), KeycloakConfigSourceProvider.getConfigSourceDisplayName(configValue.getConfigSourceName()));
|
value = maskValue(configValue.getName(), value, configValue.getConfigSourceName());
|
||||||
|
|
||||||
|
spec.commandLine().getOut().printf("\t%s = %s (%s)%n", configValue.getName(), value, KeycloakConfigSourceProvider.getConfigSourceDisplayName(configValue.getConfigSourceName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String groupProperties(String property) {
|
private static String groupProperties(String property) {
|
||||||
|
|
|
@ -100,9 +100,13 @@ public class KeycloakConfigSourceProvider implements ConfigSourceProvider, Confi
|
||||||
if (configSource == null) {
|
if (configSource == null) {
|
||||||
return "Derived";
|
return "Derived";
|
||||||
}
|
}
|
||||||
if (configSource.startsWith("KeyStoreConfigSource")) {
|
if (isKeyStoreConfigSource(configSource)) {
|
||||||
return "config-keystore";
|
return "config-keystore";
|
||||||
}
|
}
|
||||||
return CONFIG_SOURCE_DISPLAY_NAMES.getOrDefault(configSource, configSource);
|
return CONFIG_SOURCE_DISPLAY_NAMES.getOrDefault(configSource, configSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isKeyStoreConfigSource(String configSourceName) {
|
||||||
|
return configSourceName.contains("KeyStoreConfigSource");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ final class ConfigKeystorePropertyMappers {
|
||||||
.to(SMALLRYE_KEYSTORE_PASSWORD)
|
.to(SMALLRYE_KEYSTORE_PASSWORD)
|
||||||
.transformer(ConfigKeystorePropertyMappers::validatePassword)
|
.transformer(ConfigKeystorePropertyMappers::validatePassword)
|
||||||
.paramLabel("config-keystore-password")
|
.paramLabel("config-keystore-password")
|
||||||
|
.isMasked(true)
|
||||||
.build(),
|
.build(),
|
||||||
fromOption(ConfigKeystoreOptions.CONFIG_KEYSTORE_TYPE)
|
fromOption(ConfigKeystoreOptions.CONFIG_KEYSTORE_TYPE)
|
||||||
.to("smallrye.config.source.keystore.kc-default.type")
|
.to("smallrye.config.source.keystore.kc-default.type")
|
||||||
|
|
|
@ -34,6 +34,7 @@ import java.util.stream.Collectors;
|
||||||
import static org.keycloak.quarkus.runtime.Environment.isParsedCommand;
|
import static org.keycloak.quarkus.runtime.Environment.isParsedCommand;
|
||||||
import static org.keycloak.quarkus.runtime.Environment.isRebuild;
|
import static org.keycloak.quarkus.runtime.Environment.isRebuild;
|
||||||
import static org.keycloak.quarkus.runtime.Environment.isRebuildCheck;
|
import static org.keycloak.quarkus.runtime.Environment.isRebuildCheck;
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider.isKeyStoreConfigSource;
|
||||||
|
|
||||||
public final class PropertyMappers {
|
public final class PropertyMappers {
|
||||||
|
|
||||||
|
@ -125,11 +126,15 @@ public final class PropertyMappers {
|
||||||
MAPPERS.sanitizeDisabledMappers();
|
MAPPERS.sanitizeDisabledMappers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String formatValue(String property, String value) {
|
public static String maskValue(String property, String value) {
|
||||||
|
return maskValue(property, value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String maskValue(String property, String value, String configSourceName) {
|
||||||
property = removeProfilePrefixIfNeeded(property);
|
property = removeProfilePrefixIfNeeded(property);
|
||||||
PropertyMapper<?> mapper = getMapper(property);
|
PropertyMapper<?> mapper = getMapper(property);
|
||||||
|
|
||||||
if (mapper != null && mapper.isMask()) {
|
if ((configSourceName != null && isKeyStoreConfigSource(configSourceName) || (mapper != null && mapper.isMask()))) {
|
||||||
return VALUE_MASK;
|
return VALUE_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,19 @@
|
||||||
|
|
||||||
package org.keycloak.it.cli;
|
package org.keycloak.it.cli;
|
||||||
|
|
||||||
|
import io.quarkus.test.common.QuarkusTestResource;
|
||||||
|
import io.quarkus.test.junit.main.Launch;
|
||||||
|
import io.quarkus.test.junit.main.LaunchResult;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.keycloak.it.junit5.extension.CLITest;
|
import org.keycloak.it.junit5.extension.CLITest;
|
||||||
import org.keycloak.it.junit5.extension.ConfigurationTestResource;
|
import org.keycloak.it.junit5.extension.ConfigurationTestResource;
|
||||||
|
|
||||||
import io.quarkus.test.common.QuarkusTestResource;
|
|
||||||
import io.quarkus.test.junit.main.Launch;
|
|
||||||
import io.quarkus.test.junit.main.LaunchResult;
|
|
||||||
import org.keycloak.quarkus.runtime.cli.command.ShowConfig;
|
import org.keycloak.quarkus.runtime.cli.command.ShowConfig;
|
||||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.keycloak.quarkus.runtime.cli.command.Main.CONFIG_FILE_LONG_NAME;
|
import static org.keycloak.quarkus.runtime.cli.command.Main.CONFIG_FILE_LONG_NAME;
|
||||||
|
|
||||||
@QuarkusTestResource(value = ConfigurationTestResource.class, restrictToAnnotatedClass = true)
|
@QuarkusTestResource(value = ConfigurationTestResource.class, restrictToAnnotatedClass = true)
|
||||||
|
@ -59,4 +61,16 @@ public class ShowConfigCommandTest {
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Launch({ CONFIG_FILE_LONG_NAME+"=src/test/resources/ShowConfigCommandTest/keycloak-keystore.conf", ShowConfig.NAME, "all" })
|
||||||
|
void testSmallRyeKeyStoreConfigSource(LaunchResult result) {
|
||||||
|
// keystore is shared with QuarkusPropertiesDistTest#testSmallRyeKeyStoreConfigSource
|
||||||
|
String output = result.getOutput();
|
||||||
|
assertThat(output, containsString("kc.config-keystore-password = " + PropertyMappers.VALUE_MASK));
|
||||||
|
assertThat(output, containsString("kc.log-level = " + PropertyMappers.VALUE_MASK));
|
||||||
|
|
||||||
|
assertThat(output, not(containsString("secret")));
|
||||||
|
assertThat(output, not(containsString("debug")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
config-keystore=src/test/resources/keystore
|
||||||
|
config-keystore-password=secret
|
Loading…
Reference in a new issue