Skip to content

Commit

Permalink
Parse default UserProfile configuration in the build time
Browse files Browse the repository at this point in the history
Closes keycloak#24890

Signed-off-by: Martin Bartoš <[email protected]>
  • Loading branch information
mabartos authored and pedroigor committed Jan 19, 2024
1 parent e7d842e commit 98be32d
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import org.keycloak.quarkus.runtime.themes.FlatClasspathThemeResourceProviderFactory;
import org.keycloak.representations.provider.ScriptProviderDescriptor;
import org.keycloak.representations.provider.ScriptProviderMetadata;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.theme.ClasspathThemeProviderFactory;
Expand All @@ -112,6 +113,7 @@
import org.keycloak.url.DefaultHostnameProviderFactory;
import org.keycloak.url.FixedHostnameProviderFactory;
import org.keycloak.url.RequestHostnameProviderFactory;
import org.keycloak.userprofile.DeclarativeUserProfileProviderFactory;
import org.keycloak.util.JsonSerialization;
import org.keycloak.vault.FilesKeystoreVaultProviderFactory;
import org.keycloak.vault.FilesPlainTextVaultProviderFactory;
Expand All @@ -134,7 +136,6 @@
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
Expand Down Expand Up @@ -259,6 +260,27 @@ void checkJdbcDriver(BuildProducer<JdbcDriverBuildItem> ignore) {
}
}

/**
* Parse the default configuration for the User Profile provider
*/
@BuildStep
@Produce(UserProfileBuildItem.class)
UserProfileBuildItem parseDefaultUserProfileConfig() {
final UPConfig defaultConfig = DeclarativeUserProfileProviderFactory.parseDefaultConfig();
logger.debug("Parsing default configuration for the User Profile provider");
return new UserProfileBuildItem(defaultConfig);
}

/**
* Set the default configuration to the User Profile provider
*/
@BuildStep
@Consume(ProfileBuildItem.class)
@Record(ExecutionTime.STATIC_INIT)
void setDefaultUserProfileConfig(KeycloakRecorder recorder, UserProfileBuildItem configuration) {
recorder.setDefaultUserProfileConfiguration(configuration.getDefaultConfig());
}

/**
* <p>Configures the persistence unit for Quarkus.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2024 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.deployment;

import io.quarkus.builder.item.SimpleBuildItem;
import org.keycloak.representations.userprofile.config.UPConfig;

/**
* Build item that store default configuration for a User Profile provider
*/
public final class UserProfileBuildItem extends SimpleBuildItem {
private final UPConfig defaultConfig;

public UserProfileBuildItem(UPConfig defaultConfig) {
this.defaultConfig = defaultConfig;
}

public UPConfig getDefaultConfig() {
return defaultConfig;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
import org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.theme.ClasspathThemeProviderFactory;
import org.keycloak.truststore.TruststoreBuilder;

import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.ShutdownContext;
import io.quarkus.runtime.annotations.Recorder;
import liquibase.servicelocator.ServiceLocator;
import org.keycloak.userprofile.DeclarativeUserProfileProviderFactory;

@Recorder
public class KeycloakRecorder {
Expand Down Expand Up @@ -123,6 +125,10 @@ public void run() {
}
}

public void setDefaultUserProfileConfiguration(UPConfig configuration) {
DeclarativeUserProfileProviderFactory.setDefaultConfig(configuration);
}

public void registerShutdownHook(ShutdownContext shutdownContext) {
shutdownContext.addShutdownTask(new Runnable() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,12 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
private static final Pattern readOnlyAttributesPattern = getRegexPatternString(DEFAULT_READ_ONLY_ATTRIBUTES);
private static final Pattern adminReadOnlyAttributesPattern = getRegexPatternString(DEFAULT_ADMIN_READ_ONLY_ATTRIBUTES);

private UPConfig parsedDefaultRawConfig;
private static volatile UPConfig PARSED_DEFAULT_RAW_CONFIG;
private final Map<UserProfileContext, UserProfileMetadata> contextualMetadataRegistry = new HashMap<>();

public static void setDefaultConfig(UPConfig defaultConfig) {
PARSED_DEFAULT_RAW_CONFIG = defaultConfig;
}

private static boolean editUsernameCondition(AttributeContext c) {
KeycloakSession session = c.getSession();
Expand Down Expand Up @@ -203,9 +206,15 @@ public static Pattern getRegexPatternString(String[] builtinReadOnlyAttributes)
return null;
}

public static UPConfig parseDefaultConfig() {
return UPConfigUtils.parseDefaultConfig();
}

@Override
public void init(Config.Scope config) {
parsedDefaultRawConfig = UPConfigUtils.parseDefaultConfig();
if (PARSED_DEFAULT_RAW_CONFIG == null) {
setDefaultConfig(parseDefaultConfig());
}

// make sure registry is clear in case of re-deploy
contextualMetadataRegistry.clear();
Expand Down Expand Up @@ -320,7 +329,7 @@ public DeclarativeUserProfileProvider create(KeycloakSession session) {
*/
protected UserProfileMetadata configureUserProfile(UserProfileMetadata metadata) {
// default metadata for each context is based on the default realm configuration
return new DeclarativeUserProfileProvider(null, this).decorateUserProfileForCache(metadata, parsedDefaultRawConfig);
return new DeclarativeUserProfileProvider(null, this).decorateUserProfileForCache(metadata, PARSED_DEFAULT_RAW_CONFIG);
}

private AttributeValidatorMetadata createReadOnlyAttributeUnchangedValidator(Pattern pattern) {
Expand Down Expand Up @@ -469,7 +478,7 @@ private UserProfileMetadata createAccountProfile(UserProfileContext context, Att
// GETTER METHODS FOR INTERNAL FIELDS

protected UPConfig getParsedDefaultRawConfig() {
return parsedDefaultRawConfig;
return PARSED_DEFAULT_RAW_CONFIG;
}

protected Map<UserProfileContext, UserProfileMetadata> getContextualMetadataRegistry() {
Expand Down

0 comments on commit 98be32d

Please sign in to comment.