[KEYCLOAK-18255] - Vault Support in Dist.X
This commit is contained in:
parent
62482eb313
commit
eaa96f6147
38 changed files with 537 additions and 69 deletions
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak;
|
package org.keycloak;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@ -154,6 +156,11 @@ public class Config {
|
||||||
return new SystemPropertiesScope(sb.toString());
|
return new SystemPropertiesScope(sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getPropertyNames() {
|
||||||
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,5 +188,6 @@ public class Config {
|
||||||
|
|
||||||
Scope scope(String... scope);
|
Scope scope(String... scope);
|
||||||
|
|
||||||
|
Set<String> getPropertyNames();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,10 @@
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-smallrye-metrics-deployment</artifactId>
|
<artifactId>quarkus-smallrye-metrics-deployment</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-vault-deployment</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-junit5-internal</artifactId>
|
<artifactId>quarkus-junit5-internal</artifactId>
|
||||||
|
|
|
@ -556,7 +556,7 @@ class KeycloakProcessor {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (factory instanceof EnvironmentDependentProviderFactory) {
|
if (factory instanceof EnvironmentDependentProviderFactory) {
|
||||||
return ((EnvironmentDependentProviderFactory) factory).isSupported();
|
return ((EnvironmentDependentProviderFactory) factory).isSupported(scope);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,3 +4,6 @@ quarkus.banner.enabled=false
|
||||||
|
|
||||||
quarkus.resteasy.ignore-application-classes=true
|
quarkus.resteasy.ignore-application-classes=true
|
||||||
quarkus.arc.ignored-split-packages=org.keycloak.*
|
quarkus.arc.ignored-split-packages=org.keycloak.*
|
||||||
|
|
||||||
|
# we do not want running testcontainers when running tests in this module
|
||||||
|
quarkus.devservices.enabled=false
|
|
@ -71,6 +71,10 @@
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-smallrye-metrics</artifactId>
|
<artifactId>quarkus-smallrye-metrics</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-vault</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- CLI -->
|
<!-- CLI -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.quarkus.runtime;
|
package org.keycloak.quarkus.runtime;
|
||||||
|
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.getBuiltTimeProperty;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -24,14 +26,12 @@ import java.nio.file.Paths;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import io.quarkus.runtime.LaunchMode;
|
import io.quarkus.runtime.LaunchMode;
|
||||||
import io.quarkus.runtime.configuration.ProfileManager;
|
import io.quarkus.runtime.configuration.ProfileManager;
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
|
||||||
|
|
||||||
public final class Environment {
|
public final class Environment {
|
||||||
|
|
||||||
|
@ -112,16 +112,6 @@ public final class Environment {
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<String> getBuiltTimeProperty(String name) {
|
|
||||||
String value = Configuration.getBuiltTimeProperty(name);
|
|
||||||
|
|
||||||
if (value == null) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.of(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isDevMode() {
|
public static boolean isDevMode() {
|
||||||
if ("dev".equalsIgnoreCase(getProfile())) {
|
if ("dev".equalsIgnoreCase(getProfile())) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,8 +20,11 @@ package org.keycloak.quarkus.runtime.cli;
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION;
|
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
|
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.getBuiltTimeProperty;
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.getRuntimeProperty;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.isBuildTimeProperty;
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.isBuildTimeProperty;
|
||||||
import static org.keycloak.quarkus.runtime.Environment.isDevMode;
|
import static org.keycloak.quarkus.runtime.Environment.isDevMode;
|
||||||
|
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;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -70,6 +73,7 @@ public final class Picocli {
|
||||||
|
|
||||||
private static final String ARG_SEPARATOR = ";;";
|
private static final String ARG_SEPARATOR = ";;";
|
||||||
public static final String ARG_PREFIX = "--";
|
public static final String ARG_PREFIX = "--";
|
||||||
|
public static final String ARG_PART_SEPARATOR = "-";
|
||||||
public static final char ARG_KEY_VALUE_SEPARATOR = '=';
|
public static final char ARG_KEY_VALUE_SEPARATOR = '=';
|
||||||
public static final Pattern ARG_SPLIT = Pattern.compile(";;");
|
public static final Pattern ARG_SPLIT = Pattern.compile(";;");
|
||||||
public static final Pattern ARG_KEY_VALUE_SPLIT = Pattern.compile("=");
|
public static final Pattern ARG_KEY_VALUE_SPLIT = Pattern.compile("=");
|
||||||
|
@ -206,7 +210,7 @@ public final class Picocli {
|
||||||
|
|
||||||
private static boolean hasConfigChanges() {
|
private static boolean hasConfigChanges() {
|
||||||
Optional<String> currentProfile = Optional.ofNullable(Environment.getProfile());
|
Optional<String> currentProfile = Optional.ofNullable(Environment.getProfile());
|
||||||
Optional<String> persistedProfile = Environment.getBuiltTimeProperty("kc.profile");
|
Optional<String> persistedProfile = getBuiltTimeProperty("kc.profile");
|
||||||
|
|
||||||
if (!persistedProfile.orElse("").equals(currentProfile.orElse(""))) {
|
if (!persistedProfile.orElse("").equals(currentProfile.orElse(""))) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -218,16 +222,27 @@ public final class Picocli {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfigValue configValue = getConfig().getConfigValue(propertyName);
|
||||||
|
|
||||||
|
if (configValue == null || configValue.getConfigSourceName() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// try to resolve any property set using profiles
|
// try to resolve any property set using profiles
|
||||||
if (propertyName.startsWith("%")) {
|
if (propertyName.startsWith("%")) {
|
||||||
propertyName = propertyName.substring(propertyName.indexOf('.') + 1);
|
propertyName = propertyName.substring(propertyName.indexOf('.') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
String currentValue = Environment.getBuiltTimeProperty(propertyName).orElse(null);
|
String persistedValue = getBuiltTimeProperty(propertyName).orElse("");
|
||||||
String newValue = getConfig().getConfigValue(propertyName).getValue();
|
String runtimeValue = getRuntimeProperty(propertyName).orElse(null);
|
||||||
|
|
||||||
if (newValue != null && !newValue.equalsIgnoreCase(currentValue)) {
|
if (runtimeValue == null && isNotBlank(persistedValue)) {
|
||||||
// changes to a single property are enough to indicate changes to configuration
|
// probably because it was unset
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// changes to a single property is enough to indicate changes to configuration
|
||||||
|
if (!persistedValue.equals(runtimeValue)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,7 +330,8 @@ public final class Picocli {
|
||||||
String name = ARG_PREFIX + PropertyMappers.toCLIFormat(mapper.getFrom()).substring(3);
|
String name = ARG_PREFIX + PropertyMappers.toCLIFormat(mapper.getFrom()).substring(3);
|
||||||
String description = mapper.getDescription();
|
String description = mapper.getDescription();
|
||||||
|
|
||||||
if (description == null || commandSpec.optionsMap().containsKey(name)) {
|
if (description == null || commandSpec.optionsMap().containsKey(name)
|
||||||
|
|| name.endsWith(ARG_PART_SEPARATOR)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,4 +459,8 @@ public final class Picocli {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String normalizeKey(String key) {
|
||||||
|
return key.replace('-', '.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig
|
||||||
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.PropertyMappers.canonicalFormat;
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.canonicalFormat;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.formatValue;
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.formatValue;
|
||||||
import static org.keycloak.quarkus.runtime.Environment.getBuiltTimeProperty;
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.getBuiltTimeProperty;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -171,6 +171,10 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configValue.getSourceName() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
spec.commandLine().getOut().printf("\t%s = %s (%s)%n", configValue.getName(), formatValue(configValue.getName(), configValue.getValue()), configValue.getConfigSourceName());
|
spec.commandLine().getOut().printf("\t%s = %s (%s)%n", configValue.getName(), formatValue(configValue.getName(), configValue.getValue()), configValue.getConfigSourceName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_PREFIX;
|
||||||
import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_SPLIT;
|
import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_SPLIT;
|
||||||
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.MicroProfileConfigProvider.NS_QUARKUS_PREFIX;
|
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_QUARKUS_PREFIX;
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.getMappedPropertyName;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -32,6 +33,7 @@ import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import io.smallrye.config.PropertiesConfigSource;
|
import io.smallrye.config.PropertiesConfigSource;
|
||||||
import org.keycloak.quarkus.runtime.Environment;
|
import org.keycloak.quarkus.runtime.Environment;
|
||||||
|
import org.keycloak.quarkus.runtime.cli.Picocli;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A configuration source for mapping configuration arguments to their corresponding properties so that they can be recognized
|
* <p>A configuration source for mapping configuration arguments to their corresponding properties so that they can be recognized
|
||||||
|
@ -55,23 +57,13 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValue(String propertyName) {
|
public String getValue(String propertyName) {
|
||||||
String prefix = null;
|
String value = super.getValue(propertyName.replace('-', '.'));
|
||||||
|
|
||||||
// we only care about runtime args passed when executing the CLI, no need to check if the property is prefixed with a profile
|
if (value != null) {
|
||||||
if (propertyName.startsWith(NS_KEYCLOAK_PREFIX)) {
|
return value;
|
||||||
prefix = NS_KEYCLOAK_PREFIX;
|
|
||||||
} else if (propertyName.startsWith(NS_QUARKUS_PREFIX)) {
|
|
||||||
prefix = NS_QUARKUS_PREFIX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we only recognize properties within keycloak and quarkus namespaces
|
return null;
|
||||||
if (prefix == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] parts = DOT_SPLIT.split(propertyName.substring(propertyName.indexOf(prefix) + prefix.length()));
|
|
||||||
|
|
||||||
return super.getValue(prefix + String.join("-", parts));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> parseArgument() {
|
private static Map<String, String> parseArgument() {
|
||||||
|
@ -111,8 +103,10 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
|
||||||
key = NS_KEYCLOAK_PREFIX + key.substring(2);
|
key = NS_KEYCLOAK_PREFIX + key.substring(2);
|
||||||
|
|
||||||
log.tracef("Adding property [%s=%s] from command-line", key, value);
|
log.tracef("Adding property [%s=%s] from command-line", key, value);
|
||||||
|
|
||||||
properties.put(key, value);
|
properties.put(key, value);
|
||||||
|
properties.put(getMappedPropertyName(key), value);
|
||||||
|
// to make lookup easier, we normalize the key
|
||||||
|
properties.put(Picocli.normalizeKey(key), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
|
|
|
@ -42,6 +42,10 @@ public final class Configuration {
|
||||||
public static String getBuiltTimeProperty(String name) {
|
public static String getBuiltTimeProperty(String name) {
|
||||||
String value = KeycloakConfigSourceProvider.PERSISTED_CONFIG_SOURCE.getValue(name);
|
String value = KeycloakConfigSourceProvider.PERSISTED_CONFIG_SOURCE.getValue(name);
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
value = KeycloakConfigSourceProvider.PERSISTED_CONFIG_SOURCE.getValue(PropertyMappers.getMappedPropertyName(name));
|
||||||
|
}
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
String profile = Environment.getProfile();
|
String profile = Environment.getProfile();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public class EnvConfigSource implements ConfigSource {
|
||||||
|
|
||||||
|
private final Map<String, String> properties = new TreeMap<>();
|
||||||
|
|
||||||
|
public EnvConfigSource() {
|
||||||
|
for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
if (key.startsWith(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX.toUpperCase().replace('.', '_'))) {
|
||||||
|
properties.put(PropertyMappers.getMappedPropertyName(key), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 "KcEnvVarConfigSource";
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOrdinal() {
|
||||||
|
return 350;
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,9 +52,10 @@ public class KeycloakConfigSourceProvider implements ConfigSourceProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_SOURCES.add(new ConfigArgsConfigSource());
|
CONFIG_SOURCES.add(new ConfigArgsConfigSource());
|
||||||
|
CONFIG_SOURCES.add(new SysPropConfigSource());
|
||||||
|
CONFIG_SOURCES.add(new EnvConfigSource());
|
||||||
PERSISTED_CONFIG_SOURCE = new PersistedConfigSource(getPersistedConfigFile());
|
PERSISTED_CONFIG_SOURCE = new PersistedConfigSource(getPersistedConfigFile());
|
||||||
CONFIG_SOURCES.add(PERSISTED_CONFIG_SOURCE);
|
CONFIG_SOURCES.add(PERSISTED_CONFIG_SOURCE);
|
||||||
CONFIG_SOURCES.add(new SysPropConfigSource());
|
|
||||||
|
|
||||||
Path configFile = getConfigurationFile();
|
Path configFile = getConfigurationFile();
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import io.smallrye.config.PropertiesConfigSource;
|
||||||
import static org.keycloak.common.util.StringPropertyReplacer.replaceProperties;
|
import static org.keycloak.common.util.StringPropertyReplacer.replaceProperties;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK;
|
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_QUARKUS;
|
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_QUARKUS;
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMappers.getMappedPropertyName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A configuration source for {@code keycloak.properties}.
|
* A configuration source for {@code keycloak.properties}.
|
||||||
|
@ -68,7 +69,7 @@ public abstract class KeycloakPropertiesConfigSource extends PropertiesConfigSou
|
||||||
|
|
||||||
public static final class InJar extends KeycloakPropertiesConfigSource {
|
public static final class InJar extends KeycloakPropertiesConfigSource {
|
||||||
public InJar() {
|
public InJar() {
|
||||||
super(openStream(), 245);
|
super(openStream(), 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputStream openStream() {
|
private static InputStream openStream() {
|
||||||
|
@ -93,7 +94,7 @@ public abstract class KeycloakPropertiesConfigSource extends PropertiesConfigSou
|
||||||
public static final class InFileSystem extends KeycloakPropertiesConfigSource {
|
public static final class InFileSystem extends KeycloakPropertiesConfigSource {
|
||||||
|
|
||||||
public InFileSystem(Path path) {
|
public InFileSystem(Path path) {
|
||||||
super(openStream(path), 255);
|
super(openStream(path), 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputStream openStream(Path path) {
|
private static InputStream openStream(Path path) {
|
||||||
|
@ -113,7 +114,13 @@ public abstract class KeycloakPropertiesConfigSource extends PropertiesConfigSou
|
||||||
|
|
||||||
private static Map<String, String> transform(Map<String, String> properties) {
|
private static Map<String, String> transform(Map<String, String> properties) {
|
||||||
Map<String, String> result = new HashMap<>(properties.size());
|
Map<String, String> result = new HashMap<>(properties.size());
|
||||||
properties.keySet().forEach(k -> result.put(transformKey(k), replaceProperties(properties.get(k))));
|
properties.keySet().forEach(k -> {
|
||||||
|
String key = transformKey(k);
|
||||||
|
String value = replaceProperties(properties.get(k));
|
||||||
|
|
||||||
|
result.put(key, value);
|
||||||
|
result.put(getMappedPropertyName(key), value);
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,15 @@
|
||||||
|
|
||||||
package org.keycloak.quarkus.runtime.configuration;
|
package org.keycloak.quarkus.runtime.configuration;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.eclipse.microprofile.config.ConfigProvider;
|
import org.eclipse.microprofile.config.ConfigProvider;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.quarkus.runtime.cli.Picocli;
|
||||||
|
|
||||||
public class MicroProfileConfigProvider implements Config.ConfigProvider {
|
public class MicroProfileConfigProvider implements Config.ConfigProvider {
|
||||||
|
|
||||||
|
@ -109,6 +114,18 @@ public class MicroProfileConfigProvider implements Config.ConfigProvider {
|
||||||
return new MicroProfileScope(ArrayUtils.addAll(this.scope, scope));
|
return new MicroProfileScope(ArrayUtils.addAll(this.scope, scope));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getPropertyNames() {
|
||||||
|
return StreamSupport.stream(config.getPropertyNames().spliterator(), false)
|
||||||
|
.filter(new Predicate<String>() {
|
||||||
|
@Override
|
||||||
|
public boolean test(String key) {
|
||||||
|
return key.startsWith(prefix) || key.startsWith(Picocli.normalizeKey(prefix));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.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(".").concat(key)), clazz).orElse(defaultValue);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,10 +58,6 @@ public class PersistedConfigSource extends PropertiesConfigSource {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyName.startsWith(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX)) {
|
|
||||||
return super.getValue(PropertyMappers.toCLIFormat(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,13 @@ public class PropertyMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigValue getOrDefault(String name, ConfigSourceInterceptorContext context, ConfigValue current) {
|
ConfigValue getOrDefault(String name, ConfigSourceInterceptorContext context, ConfigValue current) {
|
||||||
|
String from = this.from;
|
||||||
|
|
||||||
|
if (to != null && to.endsWith(".")) {
|
||||||
|
// 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('.')));
|
||||||
|
}
|
||||||
|
|
||||||
// try to obtain the value for the property we want to map
|
// try to obtain the value for the property we want to map
|
||||||
ConfigValue config = context.proceed(from);
|
ConfigValue config = context.proceed(from);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.quarkus.runtime.configuration;
|
package org.keycloak.quarkus.runtime.configuration;
|
||||||
|
|
||||||
|
import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault;
|
||||||
|
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.Messages.invalidDatabaseVendor;
|
import static org.keycloak.quarkus.runtime.configuration.Messages.invalidDatabaseVendor;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.PropertyMapper.MAPPERS;
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMapper.MAPPERS;
|
||||||
import static org.keycloak.quarkus.runtime.configuration.PropertyMapper.create;
|
import static org.keycloak.quarkus.runtime.configuration.PropertyMapper.create;
|
||||||
|
@ -26,7 +28,9 @@ import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitia
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -34,6 +38,7 @@ import java.util.stream.Collectors;
|
||||||
import io.smallrye.config.ConfigSourceInterceptorContext;
|
import io.smallrye.config.ConfigSourceInterceptorContext;
|
||||||
import io.smallrye.config.ConfigValue;
|
import io.smallrye.config.ConfigValue;
|
||||||
|
|
||||||
|
import org.eclipse.microprofile.config.spi.ConfigSource;
|
||||||
import org.keycloak.quarkus.runtime.storage.database.Database;
|
import org.keycloak.quarkus.runtime.storage.database.Database;
|
||||||
import org.keycloak.quarkus.runtime.Environment;
|
import org.keycloak.quarkus.runtime.Environment;
|
||||||
|
|
||||||
|
@ -50,6 +55,7 @@ public final class PropertyMappers {
|
||||||
configureClustering();
|
configureClustering();
|
||||||
configureHostnameProviderMappers();
|
configureHostnameProviderMappers();
|
||||||
configureMetrics();
|
configureMetrics();
|
||||||
|
configureVault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void configureHttpPropertyMappers() {
|
private static void configureHttpPropertyMappers() {
|
||||||
|
@ -164,9 +170,45 @@ public final class PropertyMappers {
|
||||||
Arrays.asList(Boolean.TRUE.toString(), Boolean.FALSE.toString()));
|
Arrays.asList(Boolean.TRUE.toString(), Boolean.FALSE.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void configureVault() {
|
||||||
|
createBuildTimeProperty("vault.file.path", "kc.spi.vault.files-plaintext.dir", "If set, secrets can be obtained by reading the content of files within the given path.");
|
||||||
|
createBuildTimeProperty("vault.hashicorp.", "quarkus.vault.", "If set, secrets can be obtained from Hashicorp Vault.");
|
||||||
|
createBuildTimeProperty("vault.hashicorp.paths", "kc.spi.vault.hashicorp.paths", "A set of one or more paths that should be used when looking up secrets.");
|
||||||
|
}
|
||||||
|
|
||||||
static ConfigValue getValue(ConfigSourceInterceptorContext context, String name) {
|
static ConfigValue getValue(ConfigSourceInterceptorContext context, String name) {
|
||||||
return PropertyMapper.MAPPERS.getOrDefault(name, PropertyMapper.IDENTITY)
|
PropertyMapper mapper = MAPPERS.getOrDefault(name, PropertyMapper.IDENTITY);
|
||||||
|
ConfigValue configValue = mapper
|
||||||
.getOrDefault(name, context, context.proceed(name));
|
.getOrDefault(name, context, context.proceed(name));
|
||||||
|
|
||||||
|
if (configValue == null) {
|
||||||
|
Optional<String> prefixedMapper = getPrefixedMapper(name);
|
||||||
|
|
||||||
|
if (prefixedMapper.isPresent()) {
|
||||||
|
return MAPPERS.get(prefixedMapper.get()).getOrDefault(name, context, configValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
configValue.withName(mapper.getTo());
|
||||||
|
}
|
||||||
|
|
||||||
|
return configValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<String> getPrefixedMapper(String name) {
|
||||||
|
Optional<String> prefixedMapper = MAPPERS.keySet().stream().filter(new Predicate<String>() {
|
||||||
|
@Override
|
||||||
|
public boolean test(String key) {
|
||||||
|
if (!key.endsWith(".")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String prefix = key.substring(0, key.lastIndexOf('.') - 1);
|
||||||
|
|
||||||
|
return name.startsWith(prefix);
|
||||||
|
}
|
||||||
|
}).findAny();
|
||||||
|
|
||||||
|
return prefixedMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBuildTimeProperty(String name) {
|
public static boolean isBuildTimeProperty(String name) {
|
||||||
|
@ -176,8 +218,9 @@ public final class PropertyMappers {
|
||||||
}
|
}
|
||||||
|
|
||||||
return name.startsWith(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX)
|
return name.startsWith(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX)
|
||||||
&& PropertyMapper.MAPPERS.entrySet().stream()
|
&& PropertyMapper.MAPPERS.values().stream()
|
||||||
.anyMatch(entry -> entry.getValue().getFrom().equals(name) && entry.getValue().isBuildTime())
|
.filter(PropertyMapper::isBuildTime)
|
||||||
|
.anyMatch(mapper -> mapper.getFrom().equals(name) || mapper.getTo().equals(name))
|
||||||
&& !"kc.version".equals(name)
|
&& !"kc.version".equals(name)
|
||||||
&& !Environment.CLI_ARGS.equals(name)
|
&& !Environment.CLI_ARGS.equals(name)
|
||||||
&& !"kc.home.dir".equals(name)
|
&& !"kc.home.dir".equals(name)
|
||||||
|
@ -215,6 +258,10 @@ public final class PropertyMappers {
|
||||||
.filter(entry -> entry.isBuildTime()).collect(Collectors.toList());
|
.filter(entry -> entry.isBuildTime()).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Collection<PropertyMapper> getMappers() {
|
||||||
|
return MAPPERS.values();
|
||||||
|
}
|
||||||
|
|
||||||
public static String canonicalFormat(String name) {
|
public static String canonicalFormat(String name) {
|
||||||
return name.replaceAll("-", "\\.");
|
return name.replaceAll("-", "\\.");
|
||||||
}
|
}
|
||||||
|
@ -237,4 +284,58 @@ public final class PropertyMappers {
|
||||||
}
|
}
|
||||||
}).findFirst().orElse(null);
|
}).findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getMappedPropertyName(String key) {
|
||||||
|
for (PropertyMapper mapper : PropertyMappers.getMappers()) {
|
||||||
|
String mappedProperty = mapper.getFrom();
|
||||||
|
List<String> expectedFormats = Arrays.asList(mappedProperty, toCLIFormat(mappedProperty), mappedProperty.toUpperCase().replace('.', '_').replace('-', '_'));
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<String> getBuiltTimeProperty(String name) {
|
||||||
|
String value = Configuration.getBuiltTimeProperty(name);
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<String> getRuntimeProperty(String name) {
|
||||||
|
for (ConfigSource configSource : getConfig().getConfigSources()) {
|
||||||
|
if (PersistedConfigSource.NAME.equals(configSource.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = getValue(configSource, name);
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
value = getValue(configSource, PropertyMappers.getMappedPropertyName(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
return Optional.of(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getValue(ConfigSource configSource, String name) {
|
||||||
|
String value = configSource.getValue(name);
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
value = configSource.getValue("%".concat(getProfileOrDefault("prod").concat(".").concat(name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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.vault;
|
||||||
|
|
||||||
|
import static org.keycloak.vault.DefaultVaultRawSecret.forBuffer;
|
||||||
|
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.keycloak.vault.AbstractVaultProvider;
|
||||||
|
import org.keycloak.vault.VaultKeyResolver;
|
||||||
|
import org.keycloak.vault.VaultRawSecret;
|
||||||
|
|
||||||
|
import io.quarkus.vault.VaultKVSecretEngine;
|
||||||
|
|
||||||
|
public class QuarkusVaultProvider extends AbstractVaultProvider {
|
||||||
|
|
||||||
|
private VaultKVSecretEngine secretEngine;
|
||||||
|
private String[] kvPaths;
|
||||||
|
|
||||||
|
public QuarkusVaultProvider(VaultKVSecretEngine secretEngine, String[] kvPaths, String realm, List<VaultKeyResolver> keyResolvers) {
|
||||||
|
super(realm, keyResolvers);
|
||||||
|
this.secretEngine = secretEngine;
|
||||||
|
this.kvPaths = kvPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VaultRawSecret obtainSecretInternal(String key) {
|
||||||
|
if (kvPaths == null) {
|
||||||
|
return forBuffer(Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String path : kvPaths) {
|
||||||
|
Map<String, String> secrets = secretEngine.readSecret(path);
|
||||||
|
String secret = secrets.get(key);
|
||||||
|
|
||||||
|
if (secret != null) {
|
||||||
|
return forBuffer(Optional.of(StandardCharsets.UTF_8.encode(CharBuffer.wrap(secret))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return forBuffer(Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* 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.vault;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||||
|
import org.keycloak.vault.AbstractVaultProviderFactory;
|
||||||
|
import org.keycloak.vault.VaultProvider;
|
||||||
|
|
||||||
|
import io.quarkus.arc.Arc;
|
||||||
|
import io.quarkus.arc.InstanceHandle;
|
||||||
|
import io.quarkus.vault.VaultKVSecretEngine;
|
||||||
|
import io.quarkus.vault.runtime.VaultConfigHolder;
|
||||||
|
|
||||||
|
public class QuarkusVaultProviderFactory extends AbstractVaultProviderFactory implements EnvironmentDependentProviderFactory {
|
||||||
|
|
||||||
|
private String[] kvPaths;
|
||||||
|
private VaultKVSecretEngine secretEngine;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VaultProvider create(KeycloakSession session) {
|
||||||
|
return new QuarkusVaultProvider(secretEngine, kvPaths, getRealmName(session), super.keyResolvers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
super.init(config);
|
||||||
|
kvPaths = config.getArray("paths");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postInit(KeycloakSessionFactory factory) {
|
||||||
|
InstanceHandle<VaultKVSecretEngine> engineInstance = Arc.container().instance(VaultKVSecretEngine.class);
|
||||||
|
|
||||||
|
if (engineInstance.isAvailable()) {
|
||||||
|
secretEngine = engineInstance.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceHandle<VaultConfigHolder> configInstance = Arc.container().instance(VaultConfigHolder.class);
|
||||||
|
|
||||||
|
if (!configInstance.isAvailable() || configInstance.get().getVaultBootstrapConfig() == null) {
|
||||||
|
throw new RuntimeException("No configuration defined for hashicorp provider.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "hashicorp";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int order() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupported(Config.Scope config) {
|
||||||
|
return !config.getPropertyNames().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupported() {
|
||||||
|
// in quarkus we do not use this method when installing providers
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.quarkus.runtime.vault.QuarkusVaultProviderFactory
|
|
@ -42,6 +42,7 @@ import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||||
import io.quarkus.runtime.configuration.ConfigUtils;
|
import io.quarkus.runtime.configuration.ConfigUtils;
|
||||||
import io.smallrye.config.SmallRyeConfigProviderResolver;
|
import io.smallrye.config.SmallRyeConfigProviderResolver;
|
||||||
import org.keycloak.quarkus.runtime.Environment;
|
import org.keycloak.quarkus.runtime.Environment;
|
||||||
|
import org.keycloak.vault.FilesPlainTextVaultProviderFactory;
|
||||||
|
|
||||||
public class ConfigurationTest {
|
public class ConfigurationTest {
|
||||||
|
|
||||||
|
@ -175,6 +176,33 @@ public class ConfigurationTest {
|
||||||
assertEquals("http://c.jwk.url", initConfig("client-registration", "openid-connect").get("static-jwk-url"));
|
assertEquals("http://c.jwk.url", initConfig("client-registration", "openid-connect").get("static-jwk-url"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPropertyNamesFromConfig() {
|
||||||
|
System.setProperty(CLI_ARGS, "--spi-client-registration-openid-connect-static-jwk-url=http://c.jwk.url");
|
||||||
|
Config.Scope config = initConfig("client-registration", "openid-connect");
|
||||||
|
assertEquals(1, config.getPropertyNames().size());
|
||||||
|
assertEquals("http://c.jwk.url", config.get("static-jwk-url"));
|
||||||
|
|
||||||
|
System.setProperty(CLI_ARGS, "--vault-file-path=secrets");
|
||||||
|
config = initConfig("vault", FilesPlainTextVaultProviderFactory.PROVIDER_ID);
|
||||||
|
assertEquals(1, config.getPropertyNames().size());
|
||||||
|
assertEquals("secrets", config.get("dir"));
|
||||||
|
|
||||||
|
System.getProperties().remove(CLI_ARGS);
|
||||||
|
System.setProperty("kc.spi.client-registration.openid-connect.static-jwk-url", "http://c.jwk.url");
|
||||||
|
config = initConfig("client-registration", "openid-connect");
|
||||||
|
assertEquals(1, config.getPropertyNames().size());
|
||||||
|
assertEquals("http://c.jwk.url", config.get("static-jwk-url"));
|
||||||
|
|
||||||
|
System.getProperties().remove(CLI_ARGS);
|
||||||
|
System.getProperties().remove("kc.spi.client-registration.openid-connect.static-jwk-url");
|
||||||
|
putEnvVar("KC_SPI_CLIENT_REGISTRATION_OPENID_CONNECT_STATIC_JWK_URL", "http://c.jwk.url/from-env");
|
||||||
|
config = initConfig("client-registration", "openid-connect");
|
||||||
|
assertEquals(1, config.getPropertyNames().size());
|
||||||
|
assertEquals("http://c.jwk.url/from-env", config.get("static-jwk-url"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPropertyMapping() {
|
public void testPropertyMapping() {
|
||||||
System.setProperty(CLI_ARGS, "--db=mariadb" + ARG_SEPARATOR + "--db-url=jdbc:mariadb://localhost/keycloak");
|
System.setProperty(CLI_ARGS, "--db=mariadb" + ARG_SEPARATOR + "--db-url=jdbc:mariadb://localhost/keycloak");
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.component;
|
package org.keycloak.component;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import org.keycloak.Config.Scope;
|
import org.keycloak.Config.Scope;
|
||||||
import org.keycloak.component.ComponentModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -114,4 +114,9 @@ public class ComponentModelScope implements Scope {
|
||||||
return new ComponentModelScope(origScope.scope(scope), componentConfig, String.join(".", scope) + ".");
|
return new ComponentModelScope(origScope.scope(scope), componentConfig, String.join(".", scope) + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getPropertyNames() {
|
||||||
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.provider;
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Providers that are only supported in some environments can implement this interface to be able to determine if they
|
* Providers that are only supported in some environments can implement this interface to be able to determine if they
|
||||||
* should be available or not.
|
* should be available or not.
|
||||||
|
@ -27,7 +29,18 @@ public interface EnvironmentDependentProviderFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return <code>true</code> if the provider is supported and should be available, <code>false</code> otherwise
|
* @return <code>true</code> if the provider is supported and should be available, <code>false</code> otherwise
|
||||||
|
* @deprecated Prefer overriding/using the {@link #isSupported(Config.Scope)} method.
|
||||||
*/
|
*/
|
||||||
boolean isSupported();
|
boolean isSupported();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An alternative to {@link #isSupported()} method to check if the provider is supported based on the
|
||||||
|
* provider configuration.
|
||||||
|
*
|
||||||
|
* @param config the provider configuration
|
||||||
|
* @return {@code true} if the provider is supported. Otherwise, {@code false}.
|
||||||
|
*/
|
||||||
|
default boolean isSupported(Config.Scope config) {
|
||||||
|
return isSupported();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.keycloak.Config;
|
||||||
import org.keycloak.common.util.StringPropertyReplacer;
|
import org.keycloak.common.util.StringPropertyReplacer;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -183,6 +184,11 @@ public class JsonConfigProvider implements Config.ConfigProvider {
|
||||||
return new JsonScope(getNode(config, path));
|
return new JsonScope(getNode(config, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getPropertyNames() {
|
||||||
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link FilesPlainTextVaultProviderFactory}.
|
* Tests for {@link FilesPlainTextVaultProviderFactory}.
|
||||||
*
|
*
|
||||||
|
@ -129,6 +131,11 @@ public class PlainTextVaultProviderFactoryTest {
|
||||||
public Config.Scope scope(String... scope) {
|
public Config.Scope scope(String... scope) {
|
||||||
throw new UnsupportedOperationException("not implemented");
|
throw new UnsupportedOperationException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getPropertyNames() {
|
||||||
|
throw new UnsupportedOperationException("not implemented");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -113,6 +113,25 @@
|
||||||
<overwrite>true</overwrite>
|
<overwrite>true</overwrite>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>copy-vault-secrets</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-resources</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>${auth.server.home}/secrets</outputDirectory>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>${common.resources}/vault</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<overwrite>true</overwrite>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>add-extending-theme</id>
|
<id>add-extending-theme</id>
|
||||||
<phase>process-resources</phase>
|
<phase>process-resources</phase>
|
||||||
|
|
|
@ -41,3 +41,6 @@ spi.events-store.jpa.max-detail-length=2000
|
||||||
|
|
||||||
# set known protocol ports for basicsamltest
|
# set known protocol ports for basicsamltest
|
||||||
spi.login-protocol.saml.known-protocols=http=8180,https=8543
|
spi.login-protocol.saml.known-protocols=http=8180,https=8543
|
||||||
|
|
||||||
|
# File-Based Vault
|
||||||
|
vault.file.path=${kc.home.dir}secrets
|
||||||
|
|
|
@ -568,7 +568,7 @@ public class AuthServerTestEnricher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAuthServerQuarkus() && event.getTestClass().isAnnotationPresent(EnableVault.class)) {
|
if (event.getTestClass().isAnnotationPresent(EnableVault.class)) {
|
||||||
VaultUtils.enableVault(suiteContext, event.getTestClass().getAnnotation(EnableVault.class).providerId());
|
VaultUtils.enableVault(suiteContext, event.getTestClass().getAnnotation(EnableVault.class).providerId());
|
||||||
wasUpdated = true;
|
wasUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,9 @@ public class VaultTestExecutionDecider implements TestExecutionDecider {
|
||||||
if (suiteContext != null && suiteContext.getAuthServerInfo() != null && suiteContext.getAuthServerInfo().isUndertow()) {
|
if (suiteContext != null && suiteContext.getAuthServerInfo() != null && suiteContext.getAuthServerInfo().isUndertow()) {
|
||||||
return ExecutionDecision.dontExecute("@EnableVault with Elytron credential store provider not supported on Undertow, skipping");
|
return ExecutionDecision.dontExecute("@EnableVault with Elytron credential store provider not supported on Undertow, skipping");
|
||||||
}
|
}
|
||||||
|
if (suiteContext != null && suiteContext.getAuthServerInfo() != null && suiteContext.getAuthServerInfo().isQuarkus()) {
|
||||||
|
return ExecutionDecision.dontExecute("@EnableVault with Elytron credential store provider not supported on Quarkus, skipping");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ExecutionDecision.execute();
|
return ExecutionDecision.execute();
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.testsuite.util;
|
||||||
|
|
||||||
|
|
||||||
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
|
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
|
||||||
|
import org.keycloak.testsuite.arquillian.ContainerInfo;
|
||||||
import org.keycloak.testsuite.arquillian.SuiteContext;
|
import org.keycloak.testsuite.arquillian.SuiteContext;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.EnableVault;
|
import org.keycloak.testsuite.arquillian.annotation.EnableVault;
|
||||||
import org.wildfly.extras.creaper.core.online.CliException;
|
import org.wildfly.extras.creaper.core.online.CliException;
|
||||||
|
@ -34,9 +35,11 @@ import java.util.concurrent.TimeoutException;
|
||||||
public class VaultUtils {
|
public class VaultUtils {
|
||||||
|
|
||||||
public static void enableVault(SuiteContext suiteContext, EnableVault.PROVIDER_ID provider) throws IOException, CliException, TimeoutException, InterruptedException {
|
public static void enableVault(SuiteContext suiteContext, EnableVault.PROVIDER_ID provider) throws IOException, CliException, TimeoutException, InterruptedException {
|
||||||
if (suiteContext.getAuthServerInfo().isUndertow()) {
|
ContainerInfo serverInfo = suiteContext.getAuthServerInfo();
|
||||||
|
|
||||||
|
if (serverInfo.isUndertow()) {
|
||||||
System.setProperty("keycloak.vault." + provider.getName() + ".provider.enabled", "true");
|
System.setProperty("keycloak.vault." + provider.getName() + ".provider.enabled", "true");
|
||||||
} else {
|
} else if (serverInfo.isJBossBased()) {
|
||||||
OnlineManagementClient client = AuthServerTestEnricher.getManagementClient();
|
OnlineManagementClient client = AuthServerTestEnricher.getManagementClient();
|
||||||
// configure the selected provider and set it as the default vault provider.
|
// configure the selected provider and set it as the default vault provider.
|
||||||
client.execute("/subsystem=keycloak-server/spi=vault/:add(default-provider=" + provider.getName() + ")");
|
client.execute("/subsystem=keycloak-server/spi=vault/:add(default-provider=" + provider.getName() + ")");
|
||||||
|
@ -48,9 +51,11 @@ public class VaultUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void disableVault(SuiteContext suiteContext, EnableVault.PROVIDER_ID provider) throws IOException, CliException, TimeoutException, InterruptedException {
|
public static void disableVault(SuiteContext suiteContext, EnableVault.PROVIDER_ID provider) throws IOException, CliException, TimeoutException, InterruptedException {
|
||||||
if (suiteContext.getAuthServerInfo().isUndertow() || suiteContext.getAuthServerInfo().isQuarkus()) {
|
ContainerInfo serverInfo = suiteContext.getAuthServerInfo();
|
||||||
|
|
||||||
|
if (serverInfo.isUndertow()) {
|
||||||
System.setProperty("keycloak.vault." + provider.getName() + ".provider.enabled", "false");
|
System.setProperty("keycloak.vault." + provider.getName() + ".provider.enabled", "false");
|
||||||
} else {
|
} else if (serverInfo.isJBossBased()) {
|
||||||
OnlineManagementClient client = AuthServerTestEnricher.getManagementClient();
|
OnlineManagementClient client = AuthServerTestEnricher.getManagementClient();
|
||||||
for (String command : provider.getCliRemovalCommands()) {
|
for (String command : provider.getCliRemovalCommands()) {
|
||||||
client.execute(command);
|
client.execute(command);
|
||||||
|
|
|
@ -40,7 +40,7 @@ import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.A
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
@EnableVault
|
@EnableVault
|
||||||
@AuthServerContainerExclude({AuthServer.REMOTE, AuthServer.QUARKUS})
|
@AuthServerContainerExclude(AuthServer.REMOTE)
|
||||||
public class UserFederationLdapConnectionTest extends AbstractAdminTest {
|
public class UserFederationLdapConnectionTest extends AbstractAdminTest {
|
||||||
|
|
||||||
@ClassRule
|
@ClassRule
|
||||||
|
|
|
@ -39,13 +39,12 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.QUARKUS;
|
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||||
*/
|
*/
|
||||||
@AuthServerContainerExclude({REMOTE})
|
@AuthServerContainerExclude(REMOTE)
|
||||||
public class ClientSearchTest extends AbstractClientTest {
|
public class ClientSearchTest extends AbstractClientTest {
|
||||||
@ArquillianResource
|
@ArquillianResource
|
||||||
protected ContainerController controller;
|
protected ContainerController controller;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.keycloak.testsuite.broker;
|
package org.keycloak.testsuite.broker;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||||
|
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.EnableVault;
|
import org.keycloak.testsuite.arquillian.annotation.EnableVault;
|
||||||
|
|
||||||
|
@ -7,7 +9,7 @@ import org.keycloak.testsuite.arquillian.annotation.EnableVault;
|
||||||
* @author Martin Kanis <mkanis@redhat.com>
|
* @author Martin Kanis <mkanis@redhat.com>
|
||||||
*/
|
*/
|
||||||
@EnableVault
|
@EnableVault
|
||||||
@AuthServerContainerExclude({AuthServerContainerExclude.AuthServer.QUARKUS, AuthServerContainerExclude.AuthServer.REMOTE})
|
@AuthServerContainerExclude(REMOTE)
|
||||||
public class KcOidcBrokerVaultTest extends AbstractBrokerTest {
|
public class KcOidcBrokerVaultTest extends AbstractBrokerTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -50,8 +50,7 @@ import java.util.List;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test user logins utilizing various LDAP authentication methods and different LDAP connection encryption mechanisms.
|
* Test user logins utilizing various LDAP authentication methods and different LDAP connection encryption mechanisms.
|
||||||
|
@ -227,7 +226,7 @@ public class LDAPUserLoginTest extends AbstractLDAPTest {
|
||||||
// Test variant: Bind credential set to vault
|
// Test variant: Bind credential set to vault
|
||||||
@Test
|
@Test
|
||||||
@LDAPConnectionParameters(bindCredential=LDAPConnectionParameters.BindCredential.VAULT, bindType=LDAPConnectionParameters.BindType.SIMPLE, encryption=LDAPConnectionParameters.Encryption.NONE)
|
@LDAPConnectionParameters(bindCredential=LDAPConnectionParameters.BindCredential.VAULT, bindType=LDAPConnectionParameters.BindType.SIMPLE, encryption=LDAPConnectionParameters.Encryption.NONE)
|
||||||
@AuthServerContainerExclude(value = {AuthServerContainerExclude.AuthServer.QUARKUS, AuthServerContainerExclude.AuthServer.REMOTE}, details =
|
@AuthServerContainerExclude(value = REMOTE, details =
|
||||||
"java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
"java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
||||||
public void loginLDAPUserCredentialVaultAuthenticationSimpleEncryptionNone() {
|
public void loginLDAPUserCredentialVaultAuthenticationSimpleEncryptionNone() {
|
||||||
verifyConnectionUrlProtocolPrefix("ldap://");
|
verifyConnectionUrlProtocolPrefix("ldap://");
|
||||||
|
@ -247,7 +246,7 @@ public class LDAPUserLoginTest extends AbstractLDAPTest {
|
||||||
// Test variant: Bind credential set to vault
|
// Test variant: Bind credential set to vault
|
||||||
@Test
|
@Test
|
||||||
@LDAPConnectionParameters(bindCredential=LDAPConnectionParameters.BindCredential.VAULT, bindType=LDAPConnectionParameters.BindType.SIMPLE, encryption=LDAPConnectionParameters.Encryption.SSL)
|
@LDAPConnectionParameters(bindCredential=LDAPConnectionParameters.BindCredential.VAULT, bindType=LDAPConnectionParameters.BindType.SIMPLE, encryption=LDAPConnectionParameters.Encryption.SSL)
|
||||||
@AuthServerContainerExclude(value = {AuthServerContainerExclude.AuthServer.QUARKUS, AuthServerContainerExclude.AuthServer.REMOTE}, details =
|
@AuthServerContainerExclude(value = REMOTE, details =
|
||||||
"java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
"java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
||||||
public void loginLDAPUserCredentialVaultAuthenticationSimpleEncryptionSSL() {
|
public void loginLDAPUserCredentialVaultAuthenticationSimpleEncryptionSSL() {
|
||||||
verifyConnectionUrlProtocolPrefix("ldaps://");
|
verifyConnectionUrlProtocolPrefix("ldaps://");
|
||||||
|
@ -267,7 +266,7 @@ public class LDAPUserLoginTest extends AbstractLDAPTest {
|
||||||
// Test variant: Bind credential set to vault
|
// Test variant: Bind credential set to vault
|
||||||
@Test
|
@Test
|
||||||
@LDAPConnectionParameters(bindCredential=LDAPConnectionParameters.BindCredential.VAULT, bindType=LDAPConnectionParameters.BindType.SIMPLE, encryption=LDAPConnectionParameters.Encryption.STARTTLS)
|
@LDAPConnectionParameters(bindCredential=LDAPConnectionParameters.BindCredential.VAULT, bindType=LDAPConnectionParameters.BindType.SIMPLE, encryption=LDAPConnectionParameters.Encryption.STARTTLS)
|
||||||
@AuthServerContainerExclude(value = {AuthServerContainerExclude.AuthServer.QUARKUS, AuthServerContainerExclude.AuthServer.REMOTE}, details =
|
@AuthServerContainerExclude(value = REMOTE, details =
|
||||||
"java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
"java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
||||||
public void loginLDAPUserCredentialVaultAuthenticationSimpleEncryptionStartTLS() {
|
public void loginLDAPUserCredentialVaultAuthenticationSimpleEncryptionStartTLS() {
|
||||||
verifyConnectionUrlProtocolPrefix("ldap://");
|
verifyConnectionUrlProtocolPrefix("ldap://");
|
||||||
|
|
|
@ -9,12 +9,13 @@ import org.keycloak.testsuite.util.LDAPTestConfiguration;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.keycloak.models.LDAPConstants.BIND_CREDENTIAL;
|
import static org.keycloak.models.LDAPConstants.BIND_CREDENTIAL;
|
||||||
|
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author mhajas
|
* @author mhajas
|
||||||
*/
|
*/
|
||||||
@EnableVault
|
@EnableVault
|
||||||
@AuthServerContainerExclude(value = {AuthServerContainerExclude.AuthServer.QUARKUS, AuthServerContainerExclude.AuthServer.REMOTE}, details = "java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
@AuthServerContainerExclude(value = REMOTE, details = "java.io.NotSerializableException: com.sun.jndi.ldap.LdapCtx")
|
||||||
public class LDAPVaultCredentialsTest extends LDAPSyncTest {
|
public class LDAPVaultCredentialsTest extends LDAPSyncTest {
|
||||||
|
|
||||||
private static final String VAULT_EXPRESSION = "${vault.ldap_bindCredential}";
|
private static final String VAULT_EXPRESSION = "${vault.ldap_bindCredential}";
|
||||||
|
|
|
@ -60,7 +60,6 @@ import static org.junit.Assert.assertTrue;
|
||||||
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_PORT;
|
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_PORT;
|
||||||
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_SCHEME;
|
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_SCHEME;
|
||||||
import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot;
|
import static org.keycloak.testsuite.util.ServerURLs.getAuthServerContextRoot;
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.QUARKUS;
|
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||||
|
|
||||||
@AuthServerContainerExclude({REMOTE})
|
@AuthServerContainerExclude({REMOTE})
|
||||||
|
|
|
@ -32,7 +32,6 @@ import org.keycloak.vault.VaultTranscriber;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.QUARKUS;
|
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +41,7 @@ import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerEx
|
||||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||||
*/
|
*/
|
||||||
@EnableVault
|
@EnableVault
|
||||||
@AuthServerContainerExclude({REMOTE, QUARKUS})
|
@AuthServerContainerExclude(REMOTE)
|
||||||
public class KeycloakVaultTest extends AbstractKeycloakTest {
|
public class KeycloakVaultTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
|
@ -349,6 +350,11 @@ public class ElytronCSKeyStoreProviderTest {
|
||||||
public Config.Scope scope(String... scope) {
|
public Config.Scope scope(String... scope) {
|
||||||
throw new UnsupportedOperationException("not implemented");
|
throw new UnsupportedOperationException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getPropertyNames() {
|
||||||
|
throw new UnsupportedOperationException("not implemented");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SecretContains extends TypeSafeMatcher<VaultRawSecret> {
|
static class SecretContains extends TypeSafeMatcher<VaultRawSecret> {
|
||||||
|
|
Loading…
Reference in a new issue