Avoid creating the component when there is no component and configuration is not provided

Closes #20970

Co-authored-by: Pedro Igor <psilva@redhat.com>
This commit is contained in:
Pedro Igor 2023-10-05 10:08:45 -03:00 committed by Alexander Schwartz
parent 9df1c781eb
commit 7385ed56c7
7 changed files with 208 additions and 176 deletions

View file

@ -27,10 +27,13 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -103,6 +106,7 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
}
private String defaultRawConfig;
private static final Map<UserProfileContext, UserProfileMetadata> DEFAULT_METADATA = Collections.synchronizedMap(new HashMap<>());
public DeclarativeUserProfileProvider() {
defaultRawConfig = UPConfigUtils.readDefaultConfig();
@ -154,16 +158,21 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
return decoratedMetadata;
}
ComponentModel model = getComponentModelOrCreate(session);
Map<UserProfileContext, UserProfileMetadata> metadataMap = model.getNote(PARSED_CONFIG_COMPONENT_KEY);
ComponentModel component = getComponentModel().orElse(null);
if (component == null) {
return DEFAULT_METADATA.computeIfAbsent(context, (c) -> decorateUserProfileForCache(decoratedMetadata, getParsedConfig(defaultRawConfig)));
}
Map<UserProfileContext, UserProfileMetadata> metadataMap = component.getNote(PARSED_CONFIG_COMPONENT_KEY);
// not cached, create a note with cache
if (metadataMap == null) {
metadataMap = new ConcurrentHashMap<>();
model.setNote(PARSED_CONFIG_COMPONENT_KEY, metadataMap);
component.setNote(PARSED_CONFIG_COMPONENT_KEY, metadataMap);
}
return metadataMap.computeIfAbsent(context, (c) -> decorateUserProfileForCache(decoratedMetadata, model));
return metadataMap.computeIfAbsent(context, createUserDefinedProfileDecorator(session, decoratedMetadata, component));
}
@Override
@ -203,40 +212,52 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
return defaultRawConfig;
}
String cfg = getConfigJsonFromComponentModel(getComponentModel());
Optional<ComponentModel> component = getComponentModel();
if (isBlank(cfg)) {
return defaultRawConfig;
if (component.isPresent()) {
String cfg = getConfigJsonFromComponentModel(component.get());
if (isBlank(cfg)) {
return defaultRawConfig;
}
return cfg;
}
return cfg;
return defaultRawConfig;
}
@Override
public void setConfiguration(String configuration) {
ComponentModel component = getComponentModel();
RealmModel realm = session.getContext().getRealm();
Optional<ComponentModel> optionalComponent = realm.getComponentsStream(realm.getId(), UserProfileProvider.class.getName()).findAny();
if (isBlank(configuration) && !optionalComponent.isPresent()) {
return;
}
ComponentModel component = optionalComponent.isPresent() ? optionalComponent.get() : createComponentModel();
removeConfigJsonFromComponentModel(component);
RealmModel realm = session.getContext().getRealm();
if (!isBlank(configuration)) {
// store new parts
List<String> parts = UPConfigUtils.getChunks(configuration, 3800);
MultivaluedHashMap<String, String> config = component.getConfig();
config.putSingle(UP_PIECES_COUNT_COMPONENT_CONFIG_KEY, "" + parts.size());
int i = 0;
for (String part : parts) {
config.putSingle(UP_PIECE_COMPONENT_CONFIG_KEY_BASE + (i++), part);
}
realm.updateComponent(component);
} else {
if (isBlank(configuration)) {
realm.removeComponent(component);
return;
}
// store new parts
List<String> parts = UPConfigUtils.getChunks(configuration, 3800);
MultivaluedHashMap<String, String> config = component.getConfig();
config.putSingle(UP_PIECES_COUNT_COMPONENT_CONFIG_KEY, "" + parts.size());
int i = 0;
for (String part : parts) {
config.putSingle(UP_PIECE_COMPONENT_CONFIG_KEY_BASE + (i++), part);
}
realm.updateComponent(component);
}
@Override
@ -255,22 +276,18 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
return PROVIDER_PRIORITY;
}
public ComponentModel getComponentModel() {
return getComponentModelOrCreate(session);
private Optional<ComponentModel> getComponentModel() {
RealmModel realm = session.getContext().getRealm();
return realm.getComponentsStream(realm.getId(), UserProfileProvider.class.getName()).findAny();
}
/**
* Decorate basic metadata provided from {@link AbstractUserProfileProvider} based on 'per realm' configuration.
* This method is called for each {@link UserProfileContext} in each realm, and metadata are cached then and this
* method is called again only if configuration changes.
*
* @param decoratedMetadata base to be decorated based on configuration loaded from component model
* @param model component model to get "per realm" configuration from
* @return decorated metadata
*/
protected UserProfileMetadata decorateUserProfileForCache(UserProfileMetadata decoratedMetadata, ComponentModel model) {
protected UserProfileMetadata decorateUserProfileForCache(UserProfileMetadata decoratedMetadata, UPConfig parsedConfig) {
UserProfileContext context = decoratedMetadata.getContext();
UPConfig parsedConfig = getParsedConfig(model);
// do not change config for REGISTRATION_USER_CREATION context, everything important is covered thanks to REGISTRATION_PROFILE
// do not change config for UPDATE_EMAIL context, validations are already set and do not need including anything else from the configuration
@ -282,7 +299,6 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
}
Map<String, UPGroup> groupsByName = asHashMap(parsedConfig.getGroups());
RealmModel realm = session.getContext().getRealm();
int guiOrder = 0;
for (UPAttribute attrConfig : parsedConfig.getAttributes()) {
@ -346,6 +362,8 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
guiOrder++;
validators.add(new AttributeValidatorMetadata(ImmutableAttributeValidator.ID));
if (isBuiltInAttribute(attributeName)) {
// make sure username and email are writable if permissions are not set
if (permissions == null || permissions.isEmpty()) {
@ -381,14 +399,6 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
}
}
// Add ImmutableAttributeValidator to ensure that attributes that are configured
// as read-only are marked as such.
// Skip this for username in realms with username = email to allow change of email
// address on initial login with profile via idp
if (!realm.isRegistrationEmailAsUsername() && UserModel.EMAIL.equals(attributeName)) {
validators.add(new AttributeValidatorMetadata(ImmutableAttributeValidator.ID));
}
List<AttributeMetadata> existingMetadata = decoratedMetadata.getAttribute(attributeName);
if (existingMetadata.isEmpty()) {
@ -406,7 +416,6 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
.setRequired(required);
}
} else {
validators.add(new AttributeValidatorMetadata(ImmutableAttributeValidator.ID));
decoratedMetadata.addAttribute(attributeName, guiOrder, validators, selector, writeAllowed, required, readAllowed)
.addAnnotations(annotations)
.setAttributeDisplayName(attrConfig.getDisplayName())
@ -440,24 +449,11 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
/**
* Get parsed config file configured in model. Default one used if not configured.
*
* @param model to take config from
* @return parsed configuration
*/
protected UPConfig getParsedConfig(ComponentModel model) {
String rawConfig = getConfigJsonFromComponentModel(model);
protected UPConfig getParsedConfig(String rawConfig) {
if (!isBlank(rawConfig)) {
try {
UPConfig upc = parseConfig(rawConfig);
//validate configuration to catch things like changed/removed validators etc, and warn early and clearly about this problem
List<String> errors = UPConfigUtils.validate(session, upc);
if (!errors.isEmpty()) {
throw new RuntimeException("UserProfile configuration for realm '" + session.getContext().getRealm().getName() + "' is invalid: " + errors.toString());
}
return upc;
return parseConfig(rawConfig);
} catch (IOException e) {
throw new RuntimeException("UserProfile configuration for realm '" + session.getContext().getRealm().getName() + "' is invalid:" + e.getMessage(), e);
}
@ -470,23 +466,13 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
return readConfig(new ByteArrayInputStream(rawConfig.getBytes("UTF-8")));
}
/**
* Get component to store our "per realm" configuration into.
*
* @param session to be used, and take realm from
* @return component
*/
private ComponentModel getComponentModelOrCreate(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm();
return realm.getComponentsStream(realm.getId(), UserProfileProvider.class.getName()).findAny().orElseGet(() -> realm.addComponentModel(createComponentModel()));
}
/**
* Create the component model to store configuration
* @return component model
*/
protected ComponentModel createComponentModel() {
return new DeclarativeUserProfileModel(getId());
RealmModel realm = session.getContext().getRealm();
return realm.addComponentModel(new DeclarativeUserProfileModel(getId()));
}
/**
@ -538,4 +524,18 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
public boolean isEnabled(RealmModel realm) {
return isDeclarativeConfigurationEnabled && realm.getAttribute(REALM_USER_PROFILE_ENABLED, false);
}
private Function<UserProfileContext, UserProfileMetadata> createUserDefinedProfileDecorator(KeycloakSession session, UserProfileMetadata decoratedMetadata, ComponentModel component) {
return (c) -> {
UPConfig parsedConfig = getParsedConfig(getConfigJsonFromComponentModel(component));
//validate configuration to catch things like changed/removed validators etc, and warn early and clearly about this problem
List<String> errors = UPConfigUtils.validate(session, parsedConfig);
if (!errors.isEmpty()) {
throw new RuntimeException("UserProfile configuration for realm '" + session.getContext().getRealm().getName() + "' is invalid: " + errors.toString());
}
return decorateUserProfileForCache(decoratedMetadata, parsedConfig);
};
}
}

View file

@ -16,6 +16,7 @@
*/
package org.keycloak.userprofile.validator;
import static org.keycloak.common.util.CollectionUtil.collectionEquals;
import static org.keycloak.validate.Validators.notBlankValidator;
import java.util.List;
@ -23,8 +24,10 @@ import java.util.Objects;
import java.util.stream.Collectors;
import org.keycloak.common.util.CollectionUtil;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.userprofile.AttributeContext;
import org.keycloak.userprofile.AttributeValidatorMetadata;
import org.keycloak.userprofile.UserProfileAttributeValidationContext;
import org.keycloak.validate.SimpleValidator;
import org.keycloak.validate.ValidationContext;
@ -61,10 +64,27 @@ public class ImmutableAttributeValidator implements SimpleValidator {
List<String> currentValue = user.getAttributeStream(inputHint).filter(Objects::nonNull).collect(Collectors.toList());
List<String> values = (List<String>) input;
if (!CollectionUtil.collectionEquals(currentValue, values) && isReadOnly(attributeContext)) {
if (!collectionEquals(currentValue, values) && isReadOnly(attributeContext)) {
if (currentValue.isEmpty() && !notBlankValidator().validate(values).isValid()) {
return context;
}
RealmModel realm = ac.getSession().getContext().getRealm();
if (realm.isRegistrationEmailAsUsername()) {
String attributeName = attributeContext.getMetadata().getName();
if (UserModel.EMAIL.equals(attributeName)) {
return context;
}
List<String> email = attributeContext.getAttributes().getValues(UserModel.EMAIL);
if (UserModel.USERNAME.equals(attributeName) && collectionEquals(values, email)) {
return context;
}
}
context.addError(new ValidationError(ID, inputHint, DEFAULT_ERROR_MESSAGE));
}

View file

@ -2476,12 +2476,23 @@ public class UserTest extends AbstractAdminTest {
@Test
public void updateUserWithNewUsernameNotPossible() {
RealmRepresentation realmRep = realm.toRepresentation();
assertFalse(realmRep.isEditUsernameAllowed());
String id = createUser();
UserResource user = realm.users().get(id);
UserRepresentation userRep = user.toRepresentation();
userRep.setUsername("user11");
updateUser(user, userRep);
try {
updateUser(user, userRep);
if (isDeclarativeUserProfile()) {
fail("Should fail because realm does not allow edit username");
}
} catch (BadRequestException expected) {
ErrorRepresentation error = expected.getResponse().readEntity(ErrorRepresentation.class);
assertEquals("Attribute username is read only.", error.getErrorMessage());
}
userRep = realm.users().get(id).toRepresentation();
assertEquals("user1", userRep.getUsername());

View file

@ -69,6 +69,7 @@ import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import org.keycloak.testsuite.utils.tls.TLSUtils;
import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.util.JsonSerialization;
import jakarta.ws.rs.BadRequestException;
@ -87,6 +88,7 @@ import java.util.stream.Collectors;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.notNullValue;
@ -978,4 +980,21 @@ public class RealmTest extends AbstractAdminTest {
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientDbId), client, ResourceType.CLIENT);
}
@Test
public void testNoUserProfileProviderComponentUponRealmChange() {
String realmName = "new-realm";
RealmRepresentation rep = new RealmRepresentation();
rep.setRealm(realmName);
adminClient.realms().create(rep);
getCleanup().addCleanup(() -> adminClient.realms().realm(realmName).remove());
assertThat(adminClient.realm(realmName).components().query(null, UserProfileProvider.class.getName()), empty());
rep.setDisplayName("displayName");
adminClient.realm(realmName).update(rep);
// this used to return non-empty collection
assertThat(adminClient.realm(realmName).components().query(null, UserProfileProvider.class.getName()), empty());
}
}

View file

@ -25,9 +25,12 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.junit.Before;
import org.keycloak.common.Profile;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -37,10 +40,11 @@ import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.sessions.RootAuthenticationSessionModel;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
import org.keycloak.testsuite.forms.VerifyProfileTest;
import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.userprofile.config.UPAttribute;
import org.keycloak.userprofile.config.UPConfig;
import org.keycloak.userprofile.config.UPConfigUtils;
import org.keycloak.util.JsonSerialization;
/**
@ -63,12 +67,27 @@ public abstract class AbstractUserProfileTest extends AbstractTestRealmKeycloakT
session.getContext().setAuthenticationSession(createAuthenticationSession(realm.getClientByClientId(clientId), requestedScopes));
}
protected static DeclarativeUserProfileProvider getDynamicUserProfileProvider(KeycloakSession session) {
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
protected static Optional<ComponentModel> setAndGetDefaultConfiguration(KeycloakSession session) {
setDefaultConfiguration(session);
return getComponentModel(session);
}
provider.setConfiguration(null);
protected static Optional<ComponentModel> getComponentModel(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm();
return realm.getComponentsStream(realm.getId(), UserProfileProvider.class.getName()).findAny();
}
return (DeclarativeUserProfileProvider) provider;
protected static void setDefaultConfiguration(KeycloakSession session) {
setConfiguration(session, UPConfigUtils.readDefaultConfig());
}
protected static void setConfiguration(KeycloakSession session, String config) {
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(config);
}
protected static UserProfileProvider getUserProfileProvider(KeycloakSession session) {
return session.getProvider(UserProfileProvider.class);
}
/**
@ -272,4 +291,12 @@ public abstract class AbstractUserProfileTest extends AbstractTestRealmKeycloakT
}
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
}
@Before
public void resetConfigBeforeTest() {
VerifyProfileTest.disableDynamicUserProfile(testRealm());
RealmRepresentation realm = testRealm().toRepresentation();
VerifyProfileTest.enableDynamicUserProfile(realm);
testRealm().update(realm);
}
}

View file

@ -20,7 +20,6 @@
package org.keycloak.testsuite.user.profile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@ -35,10 +34,13 @@ import org.keycloak.testsuite.runonserver.RunOnServer;
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
import org.keycloak.userprofile.UserProfile;
import org.keycloak.userprofile.UserProfileContext;
import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.userprofile.config.UPConfigUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* @author <a href="mailto:joerg.matysiak@bosch.io">Jörg Matysiak</a>
@ -52,10 +54,13 @@ public class CustomUserProfileTest extends AbstractUserProfileTest {
}
private static void testCustomUserProfileProviderIsActive(KeycloakSession session) {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
assertEquals(CustomUserProfileProvider.class.getName(), provider.getClass().getName());
assertTrue(provider instanceof CustomUserProfileProvider);
assertEquals("custom-user-profile", provider.getComponentModel().getProviderId());
provider.setConfiguration(UPConfigUtils.readDefaultConfig());
Optional<ComponentModel> component = getComponentModel(session);
assertTrue(component.isPresent());
assertEquals("custom-user-profile", component.get().getProviderId());
}
@Test
@ -64,7 +69,7 @@ public class CustomUserProfileTest extends AbstractUserProfileTest {
}
private static void testInvalidConfiguration(KeycloakSession session) {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
try {
provider.setConfiguration("{\"validateConfigAttribute\": true}");
@ -80,19 +85,16 @@ public class CustomUserProfileTest extends AbstractUserProfileTest {
}
private static void testConfigurationChunks(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
String newConfig = generateLargeProfileConfig();
provider.setConfiguration(newConfig);
component = provider.getComponentModel();
Optional<ComponentModel> component = getComponentModel(session);
assertTrue(component.isPresent());
// assert config is persisted in 2 pieces
Assert.assertEquals("2", component.get(DeclarativeUserProfileProvider.UP_PIECES_COUNT_COMPONENT_CONFIG_KEY));
Assert.assertEquals("2", component.get().get(DeclarativeUserProfileProvider.UP_PIECES_COUNT_COMPONENT_CONFIG_KEY));
// assert config is returned correctly
Assert.assertEquals(newConfig, provider.getConfiguration());
}
@ -104,7 +106,7 @@ public class CustomUserProfileTest extends AbstractUserProfileTest {
}
private static void testDefaultConfig(KeycloakSession session) {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
// reset configuration to default
provider.setConfiguration(null);

View file

@ -39,6 +39,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
@ -121,7 +122,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.USERNAME, "profiled-user");
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"address\", \"required\": {}, \"permissions\": {\"edit\": [\"user\"]}}]}");
@ -157,7 +158,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.USERNAME, "profiled-user");
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"business.address\", \"required\": {\"scopes\": [\"customer\"]}, \"permissions\": {\"edit\": [\"user\"]}}]}");
@ -281,7 +282,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testValidateComplianceWithUserProfile(KeycloakSession session) throws IOException {
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, "profiled-user");
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -325,7 +326,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testGetProfileAttributes(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId());
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"address\", \"required\": {}, \"permissions\": {\"edit\": [\"user\"]}}]}");
@ -367,7 +368,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testGetProfileAttributeGroups(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId());
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
String configuration = "{\n" +
" \"attributes\": [\n" +
@ -426,7 +427,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testCreateAndUpdateUser(KeycloakSession session) throws IOException {
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = JsonSerialization.readValue(provider.getConfiguration(), UPConfig.class);
UPAttribute attribute = new UPAttribute();
@ -510,7 +511,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put("address", Arrays.asList("fixed-address"));
attributes.put("department", Arrays.asList("sales"));
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"department\", \"permissions\": {\"edit\": [\"admin\"]}}]}");
@ -559,7 +560,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
attributes.put(UserModel.EMAIL, "readonly@foo.bar");
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
// configure email r/o for user
provider.setConfiguration("{\"attributes\": [{\"name\": \"email\", \"permissions\": {\"edit\": [ \"admin\"]}}]}");
@ -601,7 +602,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
attributes.put(UserModel.EMAIL, "canchange@foo.bar");
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
// configure email r/w for user
provider.setConfiguration("{\"attributes\": [{\"name\": \"email\", \"permissions\": {\"edit\": [ \"user\", \"admin\"]}}]}");
@ -640,7 +641,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put("department", Arrays.asList("sales"));
attributes.put("phone", Arrays.asList("fixed-phone"));
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"department\", \"permissions\": {\"edit\": [\"admin\"]}},"
+ "{\"name\": \"phone\", \"permissions\": {\"edit\": [\"admin\"]}},"
@ -707,8 +708,10 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testComponentModelId(KeycloakSession session) {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
assertEquals("declarative-user-profile", provider.getComponentModel().getProviderId());
setDefaultConfiguration(session);
Optional<ComponentModel> component = getComponentModel(session);
assertTrue(component.isPresent());
assertEquals("declarative-user-profile", component.get().getProviderId());
}
@Test
@ -717,7 +720,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testInvalidConfiguration(KeycloakSession session) {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
try {
provider.setConfiguration("{\"validateConfigAttribute\": true}");
@ -734,15 +737,14 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testConfigurationChunks(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
ComponentModel component = setAndGetDefaultConfiguration(session).orElse(null);
assertNotNull(component);
String newConfig = generateLargeProfileConfig();
provider.setConfiguration(newConfig);
UserProfileProvider provider = getUserProfileProvider(session);
component = provider.getComponentModel();
provider.setConfiguration(newConfig);
component = getComponentModel(session).orElse(null);
// assert config is persisted in 2 pieces
Assert.assertEquals("2", component.get(DeclarativeUserProfileProvider.UP_PIECES_COUNT_COMPONENT_CONFIG_KEY));
@ -756,17 +758,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testResetConfiguration(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
provider.setConfiguration(null);
Assert.assertNull(provider.getComponentModel().get(DeclarativeUserProfileProvider.UP_PIECES_COUNT_COMPONENT_CONFIG_KEY));
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
Assert.assertTrue(component.getConfig().isEmpty());
setConfiguration(session, null);
assertFalse(getComponentModel(session).isPresent());
}
@Test
@ -775,7 +768,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testDefaultConfig(KeycloakSession session) {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
// reset configuration to default
provider.setConfiguration(null);
@ -825,11 +818,6 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testCustomValidationForUsername(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -843,6 +831,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addAttribute(attribute);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
@ -883,7 +872,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testRemoveDefaultValidationFromUsername(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
// reset configuration to default
provider.setConfiguration(null);
@ -926,11 +915,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testOptionalAttributes(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(UserModel.FIRST_NAME);
@ -985,11 +970,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testCustomAttributeRequired(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1052,11 +1033,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testCustomAttributeOptional(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1105,11 +1082,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testRequiredIfUser(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1172,11 +1145,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testRequiredIfAdmin(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1227,11 +1196,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testNoValidationsIfUserReadOnly(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1275,11 +1240,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testNoValidationsIfAdminReadOnly(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1320,7 +1281,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testIgnoreReadOnlyAttribute(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute firstName = new UPAttribute();
@ -1395,7 +1356,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
maria.setAttribute(LDAPConstants.LDAP_ID, List.of("1"));
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
Map<String, List<String>> attributes = new HashMap<>();
attributes.put(LDAPConstants.LDAP_ID, List.of("2"));
@ -1416,11 +1377,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testRequiredByClientScope(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1505,11 +1462,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testConfigurationInvalidScope(KeycloakSession session) throws IOException {
RealmModel realm = session.getContext().getRealm();
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
@ -1540,7 +1493,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testUsernameAndEmailPermissionNotSetIfEmpty(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = JsonSerialization.readValue(provider.getConfiguration(), UPConfig.class);
for (UPAttribute attribute : config.getAttributes()) {
@ -1581,7 +1534,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put("test-attribute", Arrays.asList("Test Value"));
attributes.put("foo", Arrays.asList("foo"));
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": ["
+ "{\"name\": \"test-attribute\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
@ -1664,7 +1617,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.FIRST_NAME, List.of(""));
attributes.put("test-attribute", List.of(""));
UserProfileProvider provider = getDynamicUserProfileProvider(session);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": ["
+ "{\"name\": \"test-attribute\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"