Remove any legacy provider from runtime when running the new store (#12963)

This commit is contained in:
Pedro Igor 2022-07-13 07:30:14 -03:00 committed by GitHub
parent 34d8629477
commit b80731decf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 507 additions and 96 deletions

View file

@ -0,0 +1,76 @@
/*
* Copyright 2022 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.models.map.stickysession;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.sessions.StickySessionEncoderProvider;
import org.keycloak.sessions.StickySessionEncoderProviderFactory;
public class DisabledStickySessionEncoderProvider implements StickySessionEncoderProviderFactory, StickySessionEncoderProvider,
EnvironmentDependentProviderFactory {
@Override
public StickySessionEncoderProvider create(KeycloakSession session) {
return this;
}
@Override
public String encodeSessionId(String sessionId) {
return sessionId;
}
@Override
public String decodeSessionId(String encodedSessionId) {
return encodedSessionId;
}
@Override
public boolean shouldAttachRoute() {
return false;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "disabled";
}
@Override
public boolean isSupported() {
return Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE);
}
}

View file

@ -0,0 +1,18 @@
#
# Copyright 2022 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.
#
org.keycloak.models.map.stickysession.DisabledStickySessionEncoderProvider

View file

@ -19,28 +19,32 @@ package org.keycloak.config;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class StorageOptions {
public enum StorageType {
legacy,
chm
chm("concurrenthashmap");
private final String provider;
StorageType(String provider) {
this.provider = provider;
}
public static final Option<Boolean> STORAGE_LEGACY_ENABLED = new OptionBuilder<>("storage-legacy-enabled", Boolean.class)
.category(OptionCategory.STORAGE)
.defaultValue(true)
.hidden()
.buildTime(true)
.build();
public String getProvider() {
return provider;
}
}
public static final Option<StorageType> STORAGE = new OptionBuilder<>("storage", StorageType.class)
.category(OptionCategory.STORAGE)
.description(String.format("Sets a storage mechanism. Possible values are: %s.",
String.join(",", String.join(", ", Arrays.stream(StorageType.values()).map(StorageType::name).collect(Collectors.toList())))))
.expectedValues(StorageType.values())
.defaultValue(StorageType.legacy)
.defaultValue(Optional.empty())
.buildTime(true)
.build();
@ -49,42 +53,98 @@ public class StorageOptions {
.buildTime(true)
.build();
public static final Option<StorageType> STORAGE_EVENT_STORE = new OptionBuilder<>("storage-event-store", StorageType.class)
.category(OptionCategory.STORAGE)
.buildTime(true)
.build();
public static final Option<StorageType> STORAGE_EVENT_ADMIN_STORE = new OptionBuilder<>("storage-event-admin", StorageType.class)
.category(OptionCategory.STORAGE)
.buildTime(true)
.build();
public static final Option<StorageType> STORAGE_EVENT_AUTH_STORE = new OptionBuilder<>("storage-event-auth", StorageType.class)
.category(OptionCategory.STORAGE)
.buildTime(true)
.build();
public static final Option<StorageType> STORAGE_EXCEPTION_CONVERTER = new OptionBuilder<>("storage-exception-converter", StorageType.class)
.category(OptionCategory.STORAGE)
.buildTime(true)
.build();
public static final Option<String> STORAGE_REALM = new OptionBuilder<>("storage-realm", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_REALM_STORE = new OptionBuilder<>("storage-realm-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CLIENT = new OptionBuilder<>("storage-client", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CLIENT_STORE = new OptionBuilder<>("storage-client-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CLIENT_SCOPE = new OptionBuilder<>("storage-client-scope", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CLIENT_SCOPE_STORE = new OptionBuilder<>("storage-client-scope-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_GROUP = new OptionBuilder<>("storage-group", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_GROUP_STORE = new OptionBuilder<>("storage-group-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_ROLE = new OptionBuilder<>("storage-role", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_ROLE_STORE = new OptionBuilder<>("storage-role-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER = new OptionBuilder<>("storage-user", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_STORE = new OptionBuilder<>("storage-user-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_DEPLOYMENT_STATE = new OptionBuilder<>("storage-deployment-state", String.class)
.category(OptionCategory.STORAGE)
.hidden()
@ -97,18 +157,36 @@ public class StorageOptions {
.buildTime(true)
.build();
public static final Option<String> STORAGE_AUTH_SESSION_STORE = new OptionBuilder<>("storage-auth-session-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_SESSION = new OptionBuilder<>("storage-user-session", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_SESSION_STORE = new OptionBuilder<>("storage-user-session-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_LOGIN_FAILURE = new OptionBuilder<>("storage-login-failure", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_LOGIN_FAILURE_STORE = new OptionBuilder<>("storage-login-failure-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_AUTHORIZATION_PERSISTER = new OptionBuilder<>("storage-authorization-persister", String.class)
.category(OptionCategory.STORAGE)
.hidden()
@ -127,12 +205,36 @@ public class StorageOptions {
.buildTime(true)
.build();
public static final Option<String> STORAGE_ACTION_TOKEN_STORE = new OptionBuilder<>("storage-action-token-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_DBLOCK = new OptionBuilder<>("storage-dblock", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<Boolean> STORAGE_CACHE_ENABLED = new OptionBuilder<>("cache-enabled", Boolean.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<Boolean> STORAGE_CACHE_CLUSTER_ENABLED = new OptionBuilder<>("cache-cluster-enabled", Boolean.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CACHE_STICK_SESSION_ENABLED = new OptionBuilder<>("cache-stick-session-enabled", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CACHE_REALM_ENABLED = new OptionBuilder<>("cache-realm-enabled", String.class)
.category(OptionCategory.STORAGE)
.hidden()
@ -145,17 +247,65 @@ public class StorageOptions {
.buildTime(true)
.build();
public static final Option<String> STORAGE_CACHE_CLEAR_USER = new OptionBuilder<>("cache-clear-user", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CACHE_CLEAR_REALM = new OptionBuilder<>("cache-clear-realm", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CACHE_CLEAR_KEYS = new OptionBuilder<>("cache-clear-keys", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_SINGLE_USE_OBJECT = new OptionBuilder<>("storage-single-use-object", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_SINGLE_USE_OBJECT_STORE = new OptionBuilder<>("storage-single-use-object-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_PUBLIC_KEY_STORE = new OptionBuilder<>("storage-public-key-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CACHE_AUTHORIZATION_ENABLED = new OptionBuilder<>("cache-authorization-enabled", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_CACHE_COMPONENT_FACTORY = new OptionBuilder<>("cache-component-factory-cache", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_LEGACY_SESSION_SUPPORT = new OptionBuilder<>("storage-legacy-session-support", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_STORAGE = new OptionBuilder<>("storage-user-storage", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final List<Option<?>> ALL_OPTIONS = List.of(STORAGE);
}

View file

@ -42,7 +42,7 @@ public class CLusteringBuildSteps {
@Consume(KeycloakSessionFactoryPreInitBuildItem.class)
@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep
@BuildStep(onlyIf = IsLegacyStoreEnabled.class)
void configureInfinispan(KeycloakRecorder recorder, BuildProducer<SyntheticBeanBuildItem> syntheticBeanBuildItems, ShutdownContextBuildItem shutdownContext) {
String configFile = getConfigValue("kc.spi-connections-infinispan-quarkus-config-file").getValue();

View file

@ -17,16 +17,20 @@
package org.keycloak.quarkus.deployment;
import static org.keycloak.config.StorageOptions.STORAGE;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getOptionalBooleanValue;
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
import java.util.function.BooleanSupplier;
import org.keycloak.config.StorageOptions;
import org.keycloak.quarkus.runtime.Environment;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
public class IsLegacyStoreEnabled implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
return getOptionalBooleanValue("kc.storage-legacy-enabled").get();
return getOptionalBooleanValue(NS_KEYCLOAK_PREFIX.concat(STORAGE.getKey())).isEmpty();
}
}

View file

@ -57,6 +57,7 @@ import io.quarkus.agroal.spi.JdbcDataSourceBuildItem;
import io.quarkus.datasource.deployment.spi.DevServicesDatasourceResultBuildItem;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.Consume;
import io.quarkus.deployment.builditem.BootstrapConfigSetupCompleteBuildItem;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
@ -277,8 +278,8 @@ class KeycloakProcessor {
*
* @param recorder
*/
@Consume(RuntimeConfigSetupCompleteBuildItem.class)
@Record(ExecutionTime.RUNTIME_INIT)
@Consume(BootstrapConfigSetupCompleteBuildItem.class)
@Record(ExecutionTime.STATIC_INIT)
@BuildStep
KeycloakSessionFactoryPreInitBuildItem configureProviders(KeycloakRecorder recorder, List<PersistenceXmlDescriptorBuildItem> descriptors) {
Profile.setInstance(new QuarkusProfile());
@ -559,8 +560,10 @@ class KeycloakProcessor {
}
}
if (!providers.isEmpty()) {
factories.put(spi, providers);
}
}
return factories;
}

View file

@ -111,6 +111,7 @@ public class KeycloakMain implements QuarkusApplication {
errorHandler.error(errStream,
String.format("Unexpected error when starting the server in (%s) mode", getKeycloakModeFromProfile(getProfileOrDefault("prod"))),
cause.getCause());
System.exit(1);
} finally {
Thread.currentThread().setContextClassLoader(originalCl);
}

View file

@ -34,8 +34,11 @@ import org.infinispan.manager.DefaultCacheManager;
import io.quarkus.smallrye.metrics.runtime.SmallRyeMetricsHandler;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.quarkus.runtime.configuration.Configuration;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
import org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory;
import org.keycloak.quarkus.runtime.storage.database.liquibase.FastServiceLocator;
import org.keycloak.provider.Provider;
@ -62,6 +65,7 @@ public class KeycloakRecorder {
Map<Class<? extends Provider>, String> defaultProviders,
Map<String, ProviderFactory> preConfiguredProviders,
Boolean reaugmented) {
Config.init(new MicroProfileConfigProvider());
Profile.setInstance(new QuarkusProfile());
QuarkusKeycloakSessionFactory.setInstance(new QuarkusKeycloakSessionFactory(factories, defaultProviders, preConfiguredProviders, reaugmented));
}

View file

@ -19,7 +19,6 @@ package org.keycloak.quarkus.runtime.cli;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_LONG;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_SHORT;
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.hasOptionValue;
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.parseConfigArgs;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuildTimeProperty;
@ -41,13 +40,11 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.keycloak.config.ConfigSupportLevel;
import org.keycloak.config.MultiOption;
import org.keycloak.config.OptionCategory;
import org.keycloak.quarkus.runtime.cli.command.Build;
@ -127,10 +124,7 @@ public final class Picocli {
public static boolean requiresReAugmentation(CommandLine cmd) {
if (hasConfigChanges()) {
Predicate<String> profileOptionMatcher = Main.PROFILE_LONG_NAME::equals;
profileOptionMatcher = profileOptionMatcher.or(Main.PROFILE_SHORT_NAME::equals);
if (hasOptionValue(profileOptionMatcher, "dev") && !ConfigArgsConfigSource.getAllCliArgs().contains(StartDev.NAME)) {
if (!ConfigArgsConfigSource.getAllCliArgs().contains(StartDev.NAME) && "dev".equals(getConfig().getOptionalValue("kc.profile", String.class).orElse(null))) {
return false;
}

View file

@ -21,23 +21,18 @@ import static java.util.Arrays.asList;
import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_SHORT_PREFIX;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_LONG;
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.AUTO_BUILD_OPTION_SHORT;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR_CHAR;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getMappedPropertyName;
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import io.smallrye.config.PropertiesConfigSource;
import org.keycloak.quarkus.runtime.cli.Picocli;
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
@ -57,12 +52,6 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
private static final String ARG_SEPARATOR = ";;";
private static final Pattern ARG_SPLIT = Pattern.compile(";;");
private static final Pattern ARG_KEY_VALUE_SPLIT = Pattern.compile("=");
private static final ConfigArgsConfigSource INSTANCE = new ConfigArgsConfigSource();
private static List<String> IGNORED_ARGS;
public static ConfigArgsConfigSource getInstance() {
return INSTANCE;
}
protected ConfigArgsConfigSource() {
super(parseArgument(), NAME, 600);
@ -104,8 +93,6 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
}
private static Map<String, String> parseArgument() {
// init here because the class might be loaded by CL without init
IGNORED_ARGS = asList("--verbose", "-v", "--help", "-h", AUTO_BUILD_OPTION_LONG, AUTO_BUILD_OPTION_SHORT);
String rawArgs = getRawConfigArgs();
if (rawArgs == null || "".equals(rawArgs.trim())) {
@ -138,22 +125,9 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
return properties;
}
public static boolean hasOptionValue(Predicate<String> keyMatcher, String expectedValue) {
AtomicBoolean result = new AtomicBoolean();
parseConfigArgs(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
if (keyMatcher.test(key) && expectedValue.equals(value)) {
result.set(true);
}
}
});
return result.get();
}
public static void parseConfigArgs(BiConsumer<String, String> cliArgConsumer) {
// init here because the class might be loaded by CL without init
List<String> ignoredArgs = asList("--verbose", "-v", "--help", "-h", AUTO_BUILD_OPTION_LONG, AUTO_BUILD_OPTION_SHORT);
String rawArgs = getRawConfigArgs();
if (rawArgs == null || "".equals(rawArgs.trim())) {
@ -165,7 +139,7 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (IGNORED_ARGS.contains(arg)) {
if (ignoredArgs.contains(arg)) {
continue;
}

View file

@ -2,9 +2,13 @@ package org.keycloak.quarkus.runtime.configuration.mappers;
import org.keycloak.common.Profile;
import org.keycloak.config.FeatureOptions;
import org.keycloak.config.StorageOptions;
import org.keycloak.quarkus.runtime.configuration.Configuration;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
import static java.util.Optional.of;
import static org.keycloak.config.StorageOptions.STORAGE;
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
import java.util.HashSet;
@ -32,7 +36,7 @@ final class FeaturePropertyMappers {
}
private static Optional<String> transformFeatures(Optional<String> features, ConfigSourceInterceptorContext context) {
if (Boolean.parseBoolean(Configuration.getRawValue("kc.storage-legacy-enabled"))) {
if (Configuration.getOptionalValue(NS_KEYCLOAK_PREFIX.concat(STORAGE.getKey())).isEmpty()) {
return features;
}

View file

@ -112,9 +112,7 @@ public class PropertyMapper<T> {
}
}
if (parentValue != null) {
return transformValue(ofNullable(parentValue.getValue()), context);
}
return transformValue(ofNullable(parentValue == null ? null : parentValue.getValue()), context);
}
ConfigValue defaultValue = transformValue(this.option.getDefaultValue().map(Objects::toString), context);

View file

@ -57,16 +57,10 @@ public final class PropertyMappers {
return true;
}
boolean isBuildTimeProperty = MAPPERS.entrySet().stream()
.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();
}
});
PropertyMapper mapper = MAPPERS.get(name);
boolean isBuildTimeProperty = mapper == null ? false : mapper.isBuildTime();
if (!isBuildTimeProperty) {
if (mapper == null && !isBuildTimeProperty) {
Optional<String> prefixedMapper = PropertyMappers.getPrefixedMapper(name);
if (prefixedMapper.isPresent()) {

View file

@ -31,19 +31,27 @@ final class StoragePropertyMappers {
public static PropertyMapper[] getMappers() {
return new PropertyMapper[] {
fromOption(StorageOptions.STORAGE_LEGACY_ENABLED)
.to("kc.spi-connections-jpa-legacy-enabled")
.mapFrom("storage")
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.transformer(StoragePropertyMappers::isDefaultPersistenceUnitEnabled)
.build(),
fromOption(StorageOptions.STORAGE)
.to("kc.spi-map-storage-provider")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_PROVIDER)
fromOption(StorageOptions.STORAGE_EVENT_STORE)
.mapFrom("storage")
.to("kc.spi-map-storage-provider")
.transformer(StoragePropertyMappers::resolveStorageProvider)
.to("kc.spi-events-store-provider")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_EVENT_ADMIN_STORE)
.mapFrom("storage")
.to("kc.spi-events-store-map-storage-admin-events-provider")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_EVENT_AUTH_STORE)
.mapFrom("storage")
.to("kc.spi-events-store-map-storage-auth-events-provider")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_REALM)
@ -52,36 +60,72 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_REALM_STORE)
.to("kc.spi-realm-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_CLIENT)
.to("kc.spi-client-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_CLIENT_STORE)
.to("kc.spi-client-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_CLIENT_SCOPE)
.to("kc.spi-client-scope-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_CLIENT_SCOPE_STORE)
.to("kc.spi-client-scope-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_GROUP)
.to("kc.spi-group-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_GROUP_STORE)
.to("kc.spi-group-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_ROLE)
.to("kc.spi-role-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_ROLE_STORE)
.to("kc.spi-role-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER)
.to("kc.spi-user-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER_STORE)
.to("kc.spi-user-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_DEPLOYMENT_STATE)
.to("kc.spi-deployment-state-provider")
.mapFrom("storage")
@ -94,18 +138,36 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::getCacheStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_AUTH_SESSION_STORE)
.to("kc.spi-authentication-sessions-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER_SESSION)
.to("kc.spi-user-sessions-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER_SESSION_STORE)
.to("kc.spi-user-sessions-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_LOGIN_FAILURE)
.to("kc.spi-login-failure-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_LOGIN_FAILURE_STORE)
.to("kc.spi-login-failure-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER_SESSION_PERSISTER)
.to("kc.spi-user-session-persister-provider")
.mapFrom("storage")
@ -124,6 +186,12 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::getCacheStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_ACTION_TOKEN_STORE)
.to("kc.spi-action-token-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_DBLOCK)
.to("kc.spi-dblock-provider")
.mapFrom("storage")
@ -154,38 +222,127 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::getCacheStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_SINGLE_USE_OBJECT_STORE)
.to("kc.spi-single-use-object-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_CACHE_COMPONENT_FACTORY)
.to("kc.spi-component-factory-default-caching-forced")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isForceComponentFactoryCache)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORE)
.to("kc.spi-public-key-storage-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_EXCEPTION_CONVERTER)
.to("kc.spi-exception-converter-jpa-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_ENABLED)
.to("kc.spi-connections-infinispan-default-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_CLUSTER_ENABLED)
.to("kc.spi-cluster-infinispan-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_STICK_SESSION_ENABLED)
.to("kc.spi-sticky-session-encoder-infinispan-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_REALM)
.to("kc.spi-admin-realm-restapi-extension-clear-realm-cache-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_USER)
.to("kc.spi-admin-realm-restapi-extension-clear-user-cache-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_KEYS)
.to("kc.spi-admin-realm-restapi-extension-clear-keys-cache-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_LEGACY_SESSION_SUPPORT)
.to("kc.spi-legacy-session-support-default-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER_STORAGE)
.to("kc.spi-admin-realm-restapi-extension-user-storage-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel("type")
.build()
};
}
private static Optional<String> isForceComponentFactoryCache(Optional<String> storage, ConfigSourceInterceptorContext context) {
if (storage.isPresent()) {
return Optional.of(Boolean.TRUE.toString());
}
return storage;
}
private static Optional<String> getAreaStorage(Optional<String> storage, ConfigSourceInterceptorContext context) {
return of("legacy".equals(storage.orElse(null)) ? "jpa" : "map");
return of(storage.isEmpty() ? "jpa" : "map");
}
private static Optional<String> getCacheStorage(Optional<String> storage, ConfigSourceInterceptorContext context) {
return of("legacy".equals(storage.orElse(null)) ? "infinispan" : "map");
return of(storage.isEmpty() ? "infinispan" : "map");
}
private static Optional<String> getDbLockProvider(Optional<String> storage, ConfigSourceInterceptorContext context) {
return of("legacy".equals(storage.orElse(null)) ? "jpa" : "none");
return of(storage.isEmpty() ? "jpa" : "none");
}
private static Optional<String> getUserSessionPersisterStorage(Optional<String> storage, ConfigSourceInterceptorContext context) {
return of("legacy".equals(storage.orElse(null)) ? "jpa" : "disabled");
return of(storage.isEmpty() ? "jpa" : "disabled");
}
private static Optional<String> isDefaultPersistenceUnitEnabled(Optional<String> value, ConfigSourceInterceptorContext context) {
if (value.get().equals(StorageOptions.StorageType.legacy.name())) {
private static Optional<String> isLegacyStoreEnabled(Optional<String> value, ConfigSourceInterceptorContext context) {
if (value.isEmpty()) {
return of(Boolean.TRUE.toString());
}
return of(Boolean.valueOf(value.get()).toString());
return of(Boolean.FALSE.toString());
}
private static Optional<String> resolveStorageProvider(Optional<String> value, ConfigSourceInterceptorContext context) {
return Optional.ofNullable("legacy".equals(value.orElse(null)) ? null : "concurrenthashmap");
private static Optional<String> resolveMapStorageProvider(Optional<String> value, ConfigSourceInterceptorContext context) {
try {
if (value.isPresent()) {
return of(value.map(StorageOptions.StorageType::valueOf).map(StorageOptions.StorageType::getProvider)
.orElse(StorageOptions.StorageType.chm.getProvider()));
}
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("Invalid storage provider: " + value.orElse(null), iae);
}
return value;
}
private static Optional<String> isCacheAreaEnabledForStorage(Optional<String> storage, ConfigSourceInterceptorContext context) {
return of("legacy".equals(storage.orElse(null)) ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
return of(storage.isEmpty() ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
}
}

View file

@ -49,6 +49,11 @@ public class QuarkusKeycloakApplication extends KeycloakApplication {
sessionFactory.publish(new PostMigrationEvent(sessionFactory));
}
@Override
protected void loadConfig() {
// no need to load config provider because we force quarkus impl
}
@Override
public Set<Object> getSingletons() {
Set<Object> singletons = super.getSingletons().stream()

View file

@ -40,6 +40,7 @@ import io.quarkus.arc.Arc;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.ServerStartupError;
import org.keycloak.common.Profile;
import org.keycloak.common.Version;
import org.keycloak.connections.jpa.DefaultJpaConnectionProvider;
import org.keycloak.connections.jpa.JpaConnectionProvider;
@ -51,6 +52,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.dblock.DBLockManager;
import org.keycloak.models.dblock.DBLockProvider;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderConfigurationBuilder;
import org.keycloak.provider.ServerInfoAwareProviderFactory;
@ -60,7 +62,8 @@ import org.keycloak.quarkus.runtime.storage.database.jpa.AbstractJpaConnectionPr
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class LegacyJpaConnectionProviderFactory extends AbstractJpaConnectionProviderFactory implements ServerInfoAwareProviderFactory {
public class LegacyJpaConnectionProviderFactory extends AbstractJpaConnectionProviderFactory implements ServerInfoAwareProviderFactory,
EnvironmentDependentProviderFactory {
public static final String QUERY_PROPERTY_PREFIX = "kc.query.";
private static final Logger logger = Logger.getLogger(LegacyJpaConnectionProviderFactory.class);
@ -309,4 +312,9 @@ public class LegacyJpaConnectionProviderFactory extends AbstractJpaConnectionPro
dbLock2.releaseLock();
}
}
@Override
public boolean isSupported() {
return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE);
}
}

View file

@ -18,12 +18,15 @@
package org.keycloak.quarkus.runtime.storage.legacy.infinispan;
import org.infinispan.manager.EmbeddedCacheManager;
import org.keycloak.common.Profile;
import org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class QuarkusInfinispanConnectionFactory extends DefaultInfinispanConnectionProviderFactory {
public class LegacyInfinispanConnectionFactory extends DefaultInfinispanConnectionProviderFactory
implements EnvironmentDependentProviderFactory {
@Override
protected void initContainerManaged(EmbeddedCacheManager cacheManager) {
@ -42,4 +45,9 @@ public class QuarkusInfinispanConnectionFactory extends DefaultInfinispanConnect
public String getId() {
return "quarkus";
}
@Override
public boolean isSupported() {
return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE);
}
}

View file

@ -18,15 +18,17 @@
package org.keycloak.quarkus.runtime.storage.legacy.liquibase;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
import org.keycloak.connections.jpa.updater.JpaUpdaterProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class QuarkusJpaUpdaterProviderFactory implements JpaUpdaterProviderFactory {
public class QuarkusJpaUpdaterProviderFactory implements JpaUpdaterProviderFactory, EnvironmentDependentProviderFactory {
@Override
public JpaUpdaterProvider create(KeycloakSession session) {
@ -55,4 +57,9 @@ public class QuarkusJpaUpdaterProviderFactory implements JpaUpdaterProviderFacto
public int order() {
return 100;
}
@Override
public boolean isSupported() {
return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE);
}
}

View file

@ -28,10 +28,12 @@ import liquibase.Scope;
import liquibase.ui.LoggerUIService;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionProvider;
import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.EnvironmentDependentProviderFactory;
import liquibase.Liquibase;
import liquibase.database.Database;
@ -44,7 +46,8 @@ import liquibase.parser.core.xml.XMLChangeLogSAXParser;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.ResourceAccessor;
public class QuarkusLiquibaseConnectionProvider implements LiquibaseConnectionProviderFactory, LiquibaseConnectionProvider {
public class QuarkusLiquibaseConnectionProvider implements LiquibaseConnectionProviderFactory, LiquibaseConnectionProvider,
EnvironmentDependentProviderFactory {
private static final Logger logger = Logger.getLogger(QuarkusLiquibaseConnectionProvider.class);
@ -149,4 +152,9 @@ public class QuarkusLiquibaseConnectionProvider implements LiquibaseConnectionPr
public int order() {
return 100;
}
@Override
public boolean isSupported() {
return !Profile.isFeatureEnabled(Profile.Feature.MAP_STORAGE);
}
}

View file

@ -17,4 +17,4 @@
# */
#
org.keycloak.quarkus.runtime.storage.legacy.infinispan.QuarkusInfinispanConnectionFactory
org.keycloak.quarkus.runtime.storage.legacy.infinispan.LegacyInfinispanConnectionFactory

View file

@ -59,7 +59,7 @@ public class OptionValidationTest {
public void failUnknownOptionWhitespaceSeparatorNotShowingValue(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
assertEquals("Unknown option: '--db-pasword'\n" +
"Possible solutions: --db-username, --db-url-host, --db-pool-min-size, --db-password, --db-url-properties, --db-url-database, --db-schema, --db-pool-max-size, --db-pool-initial-size, --db-url, --db-url-port\n" +
"Possible solutions: --db-username, --db-pool-min-size, --db-password, --db-url-database, --db-schema, --db-pool-initial-size, --db-pool-max-size, --db-url-port, --db-url, --db-url-host, --db-url-properties\n" +
"Try '" + KeycloakDistribution.SCRIPT_CMD + " start --help' for more information on the available options.", cliResult.getErrorOutput());
}
@ -68,7 +68,7 @@ public class OptionValidationTest {
public void failUnknownOptionEqualsSeparatorNotShowingValue(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
assertEquals("Unknown option: '--db-pasword'\n" +
"Possible solutions: --db-username, --db-url-host, --db-pool-min-size, --db-password, --db-url-properties, --db-url-database, --db-schema, --db-pool-max-size, --db-pool-initial-size, --db-url, --db-url-port\n" +
"Possible solutions: --db-username, --db-pool-min-size, --db-password, --db-url-database, --db-schema, --db-pool-initial-size, --db-pool-max-size, --db-url-port, --db-url, --db-url-host, --db-url-properties\n" +
"Try '" + KeycloakDistribution.SCRIPT_CMD + " start --help' for more information on the available options.", cliResult.getErrorOutput());
}
@ -77,7 +77,7 @@ public class OptionValidationTest {
public void failWithFirstOptionOnMultipleUnknownOptions(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
assertEquals("Unknown option: '--db-pasword'\n" +
"Possible solutions: --db-username, --db-url-host, --db-pool-min-size, --db-password, --db-url-properties, --db-url-database, --db-schema, --db-pool-max-size, --db-pool-initial-size, --db-url, --db-url-port\n" +
"Possible solutions: --db-username, --db-pool-min-size, --db-password, --db-url-database, --db-schema, --db-pool-initial-size, --db-pool-max-size, --db-url-port, --db-url, --db-url-host, --db-url-properties\n" +
"Try '" + KeycloakDistribution.SCRIPT_CMD + " start --help' for more information on the available options.", cliResult.getErrorOutput());
}
}

View file

@ -33,7 +33,7 @@ import org.keycloak.it.utils.KeycloakDistribution;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
@DistributionTest
@DistributionTest(reInstall = DistributionTest.ReInstall.BEFORE_TEST)
@RawDistOnly(reason = "Not possible to mount files using docker.")
public class ClusterConfigDistTest {

View file

@ -37,8 +37,7 @@ Cluster:
Storage (Experimental):
--storage <type> Experimental: Sets a storage mechanism. Possible values are: legacy, chm.
Default: legacy.
--storage <type> Experimental: Sets a storage mechanism. Possible values are: chm.
Database:

View file

@ -29,8 +29,7 @@ Cluster:
Storage (Experimental):
--storage <type> Experimental: Sets a storage mechanism. Possible values are: legacy, chm.
Default: legacy.
--storage <type> Experimental: Sets a storage mechanism. Possible values are: chm.
Database: