Update UserProfileProvider.setConfiguration. Tuning of UserProfileProvider.getConfiguration

closes #25416

Signed-off-by: mposolda <mposolda@gmail.com>
This commit is contained in:
mposolda 2023-12-13 19:21:45 +01:00 committed by Marek Posolda
parent 26342d829c
commit c81b533cf6
14 changed files with 201 additions and 145 deletions

View file

@ -19,6 +19,7 @@
package org.keycloak.representations.userprofile.config; package org.keycloak.representations.userprofile.config;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
@ -27,7 +28,7 @@ import java.util.Map;
* @author Vlastimil Elias <velias@redhat.com> * @author Vlastimil Elias <velias@redhat.com>
* *
*/ */
public class UPAttribute { public class UPAttribute implements Cloneable {
private String name; private String name;
private String displayName; private String displayName;
@ -144,4 +145,29 @@ public class UPAttribute {
public String toString() { public String toString() {
return "UPAttribute [name=" + name + ", displayName=" + displayName + ", permissions=" + permissions + ", selector=" + selector + ", required=" + required + ", validations=" + validations + ", annotations=" + annotations + ", group=" + group + "]"; return "UPAttribute [name=" + name + ", displayName=" + displayName + ", permissions=" + permissions + ", selector=" + selector + ", required=" + required + ", validations=" + validations + ", annotations=" + annotations + ", group=" + group + "]";
} }
@Override
protected UPAttribute clone() {
UPAttribute attr = new UPAttribute(this.name);
attr.setDisplayName(this.displayName);
Map<String, Map<String, Object>> validations;
if (this.validations == null) {
validations = null;
} else {
validations = new LinkedHashMap<>();
for (Map.Entry<String, Map<String, Object>> entry : this.validations.entrySet()) {
Map<String, Object> newVal = entry.getValue() == null ? null : new LinkedHashMap<>(entry.getValue());
validations.put(entry.getKey(), newVal);
}
}
attr.setValidations(validations);
attr.setAnnotations(this.annotations == null ? null : new HashMap<>(this.annotations));
attr.setRequired(this.required == null ? null : this.required.clone());
attr.setPermissions(this.permissions == null ? null : this.permissions.clone());
attr.setSelector(this.selector == null ? null : this.selector.clone());
attr.setGroup(this.group);
return attr;
}
} }

View file

@ -19,6 +19,7 @@
package org.keycloak.representations.userprofile.config; package org.keycloak.representations.userprofile.config;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
@ -28,7 +29,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
* @author Vlastimil Elias <velias@redhat.com> * @author Vlastimil Elias <velias@redhat.com>
* *
*/ */
public class UPAttributePermissions { public class UPAttributePermissions implements Cloneable {
private Set<String> view = Collections.emptySet(); private Set<String> view = Collections.emptySet();
private Set<String> edit = Collections.emptySet(); private Set<String> edit = Collections.emptySet();
@ -67,4 +68,11 @@ public class UPAttributePermissions {
public boolean isEmpty() { public boolean isEmpty() {
return getEdit().isEmpty() && getView().isEmpty(); return getEdit().isEmpty() && getView().isEmpty();
} }
@Override
protected UPAttributePermissions clone() {
Set<String> view = this.view == null ? null : new HashSet<>(this.view);
Set<String> edit = this.edit == null ? null : new HashSet<>(this.edit);
return new UPAttributePermissions(view, edit);
}
} }

View file

@ -18,6 +18,7 @@
*/ */
package org.keycloak.representations.userprofile.config; package org.keycloak.representations.userprofile.config;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
@ -28,7 +29,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
* @author Vlastimil Elias <velias@redhat.com> * @author Vlastimil Elias <velias@redhat.com>
* *
*/ */
public class UPAttributeRequired { public class UPAttributeRequired implements Cloneable {
private Set<String> roles; private Set<String> roles;
private Set<String> scopes; private Set<String> scopes;
@ -74,4 +75,11 @@ public class UPAttributeRequired {
return "UPAttributeRequired [isAlways=" + isAlways() + ", roles=" + roles + ", scopes=" + scopes + "]"; return "UPAttributeRequired [isAlways=" + isAlways() + ", roles=" + roles + ", scopes=" + scopes + "]";
} }
@Override
protected UPAttributeRequired clone() {
Set<String> scopes = this.scopes == null ? null : new HashSet<>(this.scopes);
Set<String> roles = this.roles == null ? null : new HashSet<>(this.roles);
return new UPAttributeRequired(roles, scopes);
}
} }

View file

@ -18,6 +18,7 @@
*/ */
package org.keycloak.representations.userprofile.config; package org.keycloak.representations.userprofile.config;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
@ -26,7 +27,7 @@ import java.util.Set;
* @author Vlastimil Elias <velias@redhat.com> * @author Vlastimil Elias <velias@redhat.com>
* *
*/ */
public class UPAttributeSelector { public class UPAttributeSelector implements Cloneable {
private Set<String> scopes; private Set<String> scopes;
@ -51,4 +52,8 @@ public class UPAttributeSelector {
return "UPAttributeSelector [scopes=" + scopes + "]"; return "UPAttributeSelector [scopes=" + scopes + "]";
} }
@Override
protected UPAttributeSelector clone() {
return new UPAttributeSelector(scopes == null ? null : new HashSet<>(scopes));
}
} }

View file

@ -21,6 +21,8 @@ package org.keycloak.representations.userprofile.config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
/** /**
@ -29,7 +31,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
* @author Vlastimil Elias <velias@redhat.com> * @author Vlastimil Elias <velias@redhat.com>
* *
*/ */
public class UPConfig { public class UPConfig implements Cloneable {
public enum UnmanagedAttributePolicy { public enum UnmanagedAttributePolicy {
@ -120,4 +122,19 @@ public class UPConfig {
public String toString() { public String toString() {
return "UPConfig [attributes=" + attributes + ", groups=" + groups + "]"; return "UPConfig [attributes=" + attributes + ", groups=" + groups + "]";
} }
@Override
public UPConfig clone() {
UPConfig cfg = new UPConfig();
cfg.setUnmanagedAttributePolicy(this.unmanagedAttributePolicy);
if (attributes != null) {
cfg.setAttributes(attributes.stream().map(UPAttribute::clone).collect(Collectors.toList()));
}
if (groups != null) {
cfg.setGroups(groups.stream().map(UPGroup::clone).collect(Collectors.toList()));
}
return cfg;
}
} }

View file

@ -19,6 +19,7 @@
package org.keycloak.representations.userprofile.config; package org.keycloak.representations.userprofile.config;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
@ -26,7 +27,7 @@ import java.util.Map;
* *
* @author <a href="joerg.matysiak@bosch.io">Jörg Matysiak</a> * @author <a href="joerg.matysiak@bosch.io">Jörg Matysiak</a>
*/ */
public class UPGroup { public class UPGroup implements Cloneable {
private String name; private String name;
private String displayHeader; private String displayHeader;
@ -72,4 +73,13 @@ public class UPGroup {
public void setAnnotations(Map<String, Object> annotations) { public void setAnnotations(Map<String, Object> annotations) {
this.annotations = annotations; this.annotations = annotations;
} }
@Override
protected UPGroup clone() {
UPGroup group = new UPGroup(this.name);
group.setDisplayHeader(displayHeader);
group.setDisplayDescription(displayDescription);
group.setAnnotations(this.annotations == null ? null : new HashMap<>(this.annotations));
return group;
}
} }

View file

@ -75,15 +75,7 @@ public class UIRealmResource {
return; return;
} }
String rawUpConfig; Response response = new UserProfileResource(session, auth).update(upConfig);
try {
rawUpConfig = JsonSerialization.writeValueAsString(upConfig);
} catch (IOException e) {
throw new InternalServerErrorException("Failed to parse user profile config", e);
}
Response response = new UserProfileResource(session, auth).update(rawUpConfig);
if (isSuccessful(response)) { if (isSuccessful(response)) {
return; return;

View file

@ -74,20 +74,20 @@ public interface UserProfileProvider extends Provider {
* Get current UserProfile configuration. * Get current UserProfile configuration.
* *
* @return current UserProfile configuration * @return current UserProfile configuration
* @see #setConfiguration(String) * @see #setConfiguration(UPConfig)
*/ */
UPConfig getConfiguration(); UPConfig getConfiguration();
/** /**
* Set new UserProfile configuration. It is persisted inside of the provider. * Set new UserProfile configuration. It is persisted inside of the provider.
* *
* @param configuration to be set * @param configuration to be set. It can be null and in this case, userProfile implementation will switch to use the default configuration
* @throws RuntimeException if configuration is invalid (exact exception class * @throws RuntimeException if configuration is invalid (exact exception class
* depends on the implementation) or configuration * depends on the implementation) or configuration
* can't be persisted. * can't be persisted.
* @see #getConfiguration() * @see #getConfiguration()
*/ */
void setConfiguration(String configuration); void setConfiguration(UPConfig configuration);
/** /**
* Returns whether the declarative provider is enabled to a realm * Returns whether the declarative provider is enabled to a realm

View file

@ -32,29 +32,20 @@ import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.extensions.Extension; import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
import org.eclipse.microprofile.openapi.annotations.media.Content; import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.keycloak.component.ComponentValidationException; import org.keycloak.component.ComponentValidationException;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.provider.ConfiguredProvider;
import org.keycloak.representations.idm.UserProfileAttributeGroupMetadata;
import org.keycloak.representations.idm.UserProfileAttributeMetadata;
import org.keycloak.representations.idm.UserProfileMetadata; import org.keycloak.representations.idm.UserProfileMetadata;
import org.keycloak.services.ErrorResponse; import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.KeycloakOpenAPI; import org.keycloak.services.resources.KeycloakOpenAPI;
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
import org.keycloak.userprofile.AttributeMetadata;
import org.keycloak.userprofile.AttributeValidatorMetadata;
import org.keycloak.userprofile.Attributes;
import org.keycloak.userprofile.UserProfile; import org.keycloak.userprofile.UserProfile;
import org.keycloak.userprofile.UserProfileContext; import org.keycloak.userprofile.UserProfileContext;
import org.keycloak.userprofile.UserProfileProvider; import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.representations.userprofile.config.UPConfig; import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPGroup;
import org.keycloak.validate.Validators;
/** /**
* @author Vlastimil Elias <velias@redhat.com> * @author Vlastimil Elias <velias@redhat.com>
@ -99,13 +90,12 @@ public class UserProfileResource {
@Tag(name = KeycloakOpenAPI.Admin.Tags.USERS) @Tag(name = KeycloakOpenAPI.Admin.Tags.USERS)
@Operation(description = "Set the configuration for the user profile") @Operation(description = "Set the configuration for the user profile")
@APIResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UPConfig.class))) @APIResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = UPConfig.class)))
public Response update( public Response update(UPConfig config) {
@RequestBody(content = @Content(schema = @Schema(implementation = UPConfig.class))) String text) {
auth.realm().requireManageRealm(); auth.realm().requireManageRealm();
UserProfileProvider t = session.getProvider(UserProfileProvider.class); UserProfileProvider t = session.getProvider(UserProfileProvider.class);
try { try {
t.setConfiguration(text); t.setConfiguration(config);
} catch (ComponentValidationException e) { } catch (ComponentValidationException e) {
//show validation result containing details about error //show validation result containing details about error
throw ErrorResponse.error(e.getMessage(), Response.Status.BAD_REQUEST); throw ErrorResponse.error(e.getMessage(), Response.Status.BAD_REQUEST);

View file

@ -54,6 +54,7 @@ import org.keycloak.representations.userprofile.config.UPGroup;
import org.keycloak.userprofile.validator.AttributeRequiredByMetadataValidator; import org.keycloak.userprofile.validator.AttributeRequiredByMetadataValidator;
import org.keycloak.userprofile.validator.BlankAttributeValidator; import org.keycloak.userprofile.validator.BlankAttributeValidator;
import org.keycloak.userprofile.validator.ImmutableAttributeValidator; import org.keycloak.userprofile.validator.ImmutableAttributeValidator;
import org.keycloak.util.JsonSerialization;
import org.keycloak.validate.AbstractSimpleValidator; import org.keycloak.validate.AbstractSimpleValidator;
import org.keycloak.validate.ValidatorConfig; import org.keycloak.validate.ValidatorConfig;
@ -68,7 +69,8 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
public static final String UP_COMPONENT_CONFIG_KEY = "kc.user.profile.config"; public static final String UP_COMPONENT_CONFIG_KEY = "kc.user.profile.config";
public static final String REALM_USER_PROFILE_ENABLED = "userProfileEnabled"; public static final String REALM_USER_PROFILE_ENABLED = "userProfileEnabled";
protected static final String PARSED_CONFIG_COMPONENT_KEY = "kc.user.profile.metadata"; // TODO:mposolda should it be here or rather on factory? protected static final String PARSED_CONFIG_COMPONENT_KEY = "kc.user.profile.metadata";
protected static final String PARSED_UP_CONFIG_COMPONENT_KEY = "kc.parsed.up.config";
/** /**
* Method used for predicate which returns true if any of the configuredScopes is requested in current auth flow. * Method used for predicate which returns true if any of the configuredScopes is requested in current auth flow.
@ -95,7 +97,6 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
private final boolean isDeclarativeConfigurationEnabled; private final boolean isDeclarativeConfigurationEnabled;
private final String providerId; private final String providerId;
private final Map<UserProfileContext, UserProfileMetadata> contextualMetadataRegistry; private final Map<UserProfileContext, UserProfileMetadata> contextualMetadataRegistry;
private final String defaultRawConfig;
protected final UPConfig parsedDefaultRawConfig; protected final UPConfig parsedDefaultRawConfig;
public DeclarativeUserProfileProvider(KeycloakSession session, DeclarativeUserProfileProviderFactory factory) { public DeclarativeUserProfileProvider(KeycloakSession session, DeclarativeUserProfileProviderFactory factory) {
@ -103,7 +104,6 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
this.providerId = factory.getId(); this.providerId = factory.getId();
this.isDeclarativeConfigurationEnabled = factory.isDeclarativeConfigurationEnabled(); this.isDeclarativeConfigurationEnabled = factory.isDeclarativeConfigurationEnabled();
this.contextualMetadataRegistry = factory.getContextualMetadataRegistry(); this.contextualMetadataRegistry = factory.getContextualMetadataRegistry();
this.defaultRawConfig = factory.getDefaultRawConfig();
this.parsedDefaultRawConfig = factory.getParsedDefaultRawConfig(); this.parsedDefaultRawConfig = factory.getParsedDefaultRawConfig();
} }
@ -214,42 +214,41 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
if (!isEnabled(realm)) { if (!isEnabled(realm)) {
return getParsedConfig(defaultRawConfig); return parsedDefaultRawConfig.clone();
} }
Optional<ComponentModel> component = getComponentModel(); Optional<ComponentModel> component = getComponentModel();
if (component.isPresent()) { if (component.isPresent()) {
String cfg = getConfigJsonFromComponentModel(component.get()); UPConfig cfg = getConfigFromComponentModel(component.get()).clone();
return cfg == null ? parsedDefaultRawConfig.clone() : cfg;
if (isBlank(cfg)) {
return getParsedConfig(defaultRawConfig);
}
return getParsedConfig(cfg);
} }
return getParsedConfig(defaultRawConfig); return parsedDefaultRawConfig.clone();
} }
@Override @Override
public void setConfiguration(String configuration) { public void setConfiguration(UPConfig configuration) {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
Optional<ComponentModel> optionalComponent = realm.getComponentsStream(realm.getId(), UserProfileProvider.class.getName()).findAny(); Optional<ComponentModel> optionalComponent = realm.getComponentsStream(realm.getId(), UserProfileProvider.class.getName()).findAny();
// Avoid creating componentModel and then removing it right away // Avoid creating componentModel and then removing it right away
if (!optionalComponent.isPresent() && isBlank(configuration)) return; if (!optionalComponent.isPresent() && configuration == null) return;
ComponentModel component = optionalComponent.isPresent() ? optionalComponent.get() : createComponentModel(); ComponentModel component = optionalComponent.isPresent() ? optionalComponent.get() : createComponentModel();
removeConfigJsonFromComponentModel(component); removeConfigJsonFromComponentModel(component);
if (isBlank(configuration)) { if (configuration == null) {
realm.removeComponent(component); realm.removeComponent(component);
return; return;
} }
component.getConfig().putSingle(UP_COMPONENT_CONFIG_KEY, configuration); try {
component.getConfig().putSingle(UP_COMPONENT_CONFIG_KEY, JsonSerialization.writeValueAsString(configuration));
} catch (IOException ioe) {
throw new RuntimeException("Cannot write component config", ioe);
}
realm.updateComponent(component); realm.updateComponent(component);
} }
@ -475,11 +474,23 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
return new AttributeValidatorMetadata(validator, ValidatorConfig.builder().config(validatorConfig).config(AbstractSimpleValidator.IGNORE_EMPTY_VALUE, true).build()); return new AttributeValidatorMetadata(validator, ValidatorConfig.builder().config(validatorConfig).config(AbstractSimpleValidator.IGNORE_EMPTY_VALUE, true).build());
} }
private String getConfigJsonFromComponentModel(ComponentModel model) { private UPConfig getConfigFromComponentModel(ComponentModel model) {
if (model == null) if (model == null)
return null; return null;
return model.get(UP_COMPONENT_CONFIG_KEY); UPConfig cfg = model.getNote(PARSED_UP_CONFIG_COMPONENT_KEY);
if (cfg != null) {
return cfg;
}
String rawConfig = model.get(UP_COMPONENT_CONFIG_KEY);
if (rawConfig == null) {
return null;
} else {
cfg = getParsedConfig(rawConfig);
model.setNote(PARSED_UP_CONFIG_COMPONENT_KEY, cfg);
return cfg;
}
} }
private void removeConfigJsonFromComponentModel(ComponentModel model) { private void removeConfigJsonFromComponentModel(ComponentModel model) {
@ -500,7 +511,7 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
private Function<UserProfileContext, UserProfileMetadata> createUserDefinedProfileDecorator(KeycloakSession session, UserProfileMetadata decoratedMetadata, ComponentModel component) { private Function<UserProfileContext, UserProfileMetadata> createUserDefinedProfileDecorator(KeycloakSession session, UserProfileMetadata decoratedMetadata, ComponentModel component) {
return (c) -> { return (c) -> {
UPConfig parsedConfig = getParsedConfig(getConfigJsonFromComponentModel(component)); UPConfig parsedConfig = getConfigFromComponentModel(component);
//validate configuration to catch things like changed/removed validators etc, and warn early and clearly about this problem //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); List<String> errors = UPConfigUtils.validate(session, parsedConfig);

View file

@ -87,7 +87,6 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
private boolean isDeclarativeConfigurationEnabled; private boolean isDeclarativeConfigurationEnabled;
private String defaultRawConfig;
private UPConfig parsedDefaultRawConfig; private UPConfig parsedDefaultRawConfig;
private final Map<UserProfileContext, UserProfileMetadata> contextualMetadataRegistry = new HashMap<>(); private final Map<UserProfileContext, UserProfileMetadata> contextualMetadataRegistry = new HashMap<>();
@ -200,12 +199,7 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
@Override @Override
public void init(Config.Scope config) { public void init(Config.Scope config) {
isDeclarativeConfigurationEnabled = Profile.isFeatureEnabled(Profile.Feature.DECLARATIVE_USER_PROFILE); isDeclarativeConfigurationEnabled = Profile.isFeatureEnabled(Profile.Feature.DECLARATIVE_USER_PROFILE);
defaultRawConfig = UPConfigUtils.readDefaultConfig(); parsedDefaultRawConfig = UPConfigUtils.parseDefaultConfig();
try {
parsedDefaultRawConfig = UPConfigUtils.parseConfig(defaultRawConfig);
} catch (IOException cause) {
throw new RuntimeException("Failed to parse default user profile configuration", cause);
}
// make sure registry is clear in case of re-deploy // make sure registry is clear in case of re-deploy
contextualMetadataRegistry.clear(); contextualMetadataRegistry.clear();
@ -446,10 +440,6 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
return isDeclarativeConfigurationEnabled; return isDeclarativeConfigurationEnabled;
} }
protected String getDefaultRawConfig() {
return defaultRawConfig;
}
protected UPConfig getParsedDefaultRawConfig() { protected UPConfig getParsedDefaultRawConfig() {
return parsedDefaultRawConfig; return parsedDefaultRawConfig;
} }

View file

@ -83,7 +83,12 @@ public abstract class AbstractUserProfileTest extends AbstractTestRealmKeycloakT
protected static void setConfiguration(KeycloakSession session, String config) { protected static void setConfiguration(KeycloakSession session, String config) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(config); try {
UPConfig upConfig = config == null ? null : UPConfigUtils.parseConfig(config);
provider.setConfiguration(upConfig);
} catch (IOException ioe) {
throw new RuntimeException("Error when parsing user-profile config: " + config, ioe);
}
} }
protected static UserProfileProvider getUserProfileProvider(KeycloakSession session) { protected static UserProfileProvider getUserProfileProvider(KeycloakSession session) {

View file

@ -54,7 +54,7 @@ public class CustomUserProfileTest extends AbstractUserProfileTest {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
assertEquals(CustomUserProfileProvider.class.getName(), provider.getClass().getName()); assertEquals(CustomUserProfileProvider.class.getName(), provider.getClass().getName());
assertTrue(provider instanceof CustomUserProfileProvider); assertTrue(provider instanceof CustomUserProfileProvider);
provider.setConfiguration(UPConfigUtils.readDefaultConfig()); provider.setConfiguration(UPConfigUtils.parseDefaultConfig());
Optional<ComponentModel> component = getComponentModel(session); Optional<ComponentModel> component = getComponentModel(session);
assertTrue(component.isPresent()); assertTrue(component.isPresent());
assertEquals("custom-user-profile", component.get().getProviderId()); assertEquals("custom-user-profile", component.get().getProviderId());
@ -66,12 +66,10 @@ public class CustomUserProfileTest extends AbstractUserProfileTest {
} }
private static void testInvalidConfiguration(KeycloakSession session) { private static void testInvalidConfiguration(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session);
try { try {
provider.setConfiguration("{\"validateConfigAttribute\": true}"); setConfiguration(session, "{\"validateConfigAttribute\": true}");
fail("Should fail validation"); fail("Should fail validation");
} catch (ComponentValidationException ve) { } catch (RuntimeException ve) {
// OK // OK
} }
} }

View file

@ -32,7 +32,6 @@ import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_USER;
import static org.keycloak.userprofile.config.UPConfigUtils.parseDefaultConfig; import static org.keycloak.userprofile.config.UPConfigUtils.parseDefaultConfig;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -79,7 +78,6 @@ import org.keycloak.userprofile.UserProfileContext;
import org.keycloak.userprofile.UserProfileProvider; import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.userprofile.ValidationException; import org.keycloak.userprofile.ValidationException;
import org.keycloak.userprofile.validator.UsernameIDNHomographValidator; import org.keycloak.userprofile.validator.UsernameIDNHomographValidator;
import org.keycloak.util.JsonSerialization;
import org.keycloak.validate.ValidationError; import org.keycloak.validate.ValidationError;
import org.keycloak.validate.validators.EmailValidator; import org.keycloak.validate.validators.EmailValidator;
import org.keycloak.validate.validators.LengthValidator; import org.keycloak.validate.validators.LengthValidator;
@ -138,7 +136,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
UPConfig upConfig = provider.getConfiguration(); UPConfig upConfig = provider.getConfiguration();
upConfig.getAttribute("foo") upConfig.getAttribute("foo")
.setValidations(Map.of("length", Map.of("min", "5", "max", "15"))); .setValidations(Map.of("length", Map.of("min", "5", "max", "15")));
provider.setConfiguration(JsonSerialization.writeValueAsString(upConfig)); provider.setConfiguration(upConfig);
Map<String, List<String>> attributes = new HashMap<>(user.getAttributes()); Map<String, List<String>> attributes = new HashMap<>(user.getAttributes());
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user); UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
profile.validate(); profile.validate();
@ -165,7 +163,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
UPAttribute changedFoo = upConfig.getAttribute("foo"); UPAttribute changedFoo = upConfig.getAttribute("foo");
changedFoo.setPermissions(new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN))); changedFoo.setPermissions(new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN)));
changedFoo.setValidations(Map.of("length", Map.of("min", "5", "max", "15"))); changedFoo.setValidations(Map.of("length", Map.of("min", "5", "max", "15")));
provider.setConfiguration(JsonSerialization.writeValueAsString(upConfig)); provider.setConfiguration(upConfig);
Map<String, List<String>> attributes = new HashMap<>(user.getAttributes()); Map<String, List<String>> attributes = new HashMap<>(user.getAttributes());
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user); UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
@ -196,7 +194,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomAttributeInAnyContext); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomAttributeInAnyContext);
} }
private static void testCustomAttributeInAnyContext(KeycloakSession session) throws IOException { private static void testCustomAttributeInAnyContext(KeycloakSession session) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, "profiled-user"); attributes.put(UserModel.USERNAME, "profiled-user");
@ -207,7 +205,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired())); config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes); UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
@ -235,7 +233,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testResolveProfile); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testResolveProfile);
} }
private static void testResolveProfile(KeycloakSession session) throws IOException { private static void testResolveProfile(KeycloakSession session) {
configureAuthenticationSession(session); configureAuthenticationSession(session);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -248,7 +246,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("business.address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(), Set.of("customer")))); config.addOrReplaceAttribute(new UPAttribute("business.address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(), Set.of("customer"))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes); UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
@ -276,7 +274,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testAttributeValidation); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testAttributeValidation);
} }
private static void failValidationWhenEmptyAttributes(KeycloakSession session) throws IOException { private static void failValidationWhenEmptyAttributes(KeycloakSession session) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
UserProfileProvider provider = session.getProvider(UserProfileProvider.class); UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
provider.setConfiguration(null); provider.setConfiguration(null);
@ -325,7 +323,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
email.setRequired(null); email.setRequired(null);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
attributes.clear(); attributes.clear();
attributes.put(UserModel.USERNAME, "profile-user"); attributes.put(UserModel.USERNAME, "profile-user");
@ -367,14 +365,14 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testValidateComplianceWithUserProfile); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testValidateComplianceWithUserProfile);
} }
private static void testValidateComplianceWithUserProfile(KeycloakSession session) throws IOException { private static void testValidateComplianceWithUserProfile(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, "profiled-user"); UserModel user = session.users().addUser(realm, "profiled-user");
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired())); config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user); UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user);
@ -401,7 +399,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testGetProfileAttributes); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testGetProfileAttributes);
} }
private static void testGetProfileAttributes(KeycloakSession session) throws IOException { private static void testGetProfileAttributes(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId()); UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId());
user.setFirstName("John"); user.setFirstName("John");
@ -411,7 +409,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired())); config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user); UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user);
Attributes attributes = profile.getAttributes(); Attributes attributes = profile.getAttributes();
@ -448,7 +446,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testGetProfileAttributeGroups); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testGetProfileAttributeGroups);
} }
private static void testGetProfileAttributeGroups(KeycloakSession session) throws IOException { private static void testGetProfileAttributeGroups(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId()); UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId());
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
@ -462,7 +460,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
groupWithAnnotation.setAnnotations(Map.of("anno1", "value1", "anno2", "value2")); groupWithAnnotation.setAnnotations(Map.of("anno1", "value1", "anno2", "value2"));
config.addGroup(groupWithAnnotation); config.addGroup(groupWithAnnotation);
config.addOrReplaceAttribute(new UPAttribute("second", groupWithAnnotation)); config.addOrReplaceAttribute(new UPAttribute("second", groupWithAnnotation));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user); UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user);
Attributes attributes = profile.getAttributes(); Attributes attributes = profile.getAttributes();
@ -492,13 +490,13 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCreateAndUpdateUser); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCreateAndUpdateUser);
} }
private static void testCreateAndUpdateUser(KeycloakSession session) throws IOException { private static void testCreateAndUpdateUser(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = provider.getConfiguration(); UPConfig config = provider.getConfiguration();
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER)))); config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER))));
config.addOrReplaceAttribute(new UPAttribute("business.address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER)))); config.addOrReplaceAttribute(new UPAttribute("business.address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
String userName = org.keycloak.models.utils.KeycloakModelUtils.generateId(); String userName = org.keycloak.models.utils.KeycloakModelUtils.generateId();
@ -558,7 +556,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadonlyUpdates); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadonlyUpdates);
} }
private static void testReadonlyUpdates(KeycloakSession session) throws IOException { private static void testReadonlyUpdates(KeycloakSession session) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId()); attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -571,7 +569,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("department", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("department", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes); UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create(); UserModel user = profile.create();
@ -612,7 +610,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadonlyEmailCannotBeUpdated); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadonlyEmailCannotBeUpdated);
} }
private static void testReadonlyEmailCannotBeUpdated(KeycloakSession session) throws IOException { private static void testReadonlyEmailCannotBeUpdated(KeycloakSession session) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId()); attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -625,7 +623,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addOrReplaceAttribute(new UPAttribute("email", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("email", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
// configure email r/o for user // configure email r/o for user
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes); UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create(); UserModel user = profile.create();
@ -661,7 +659,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testUpdateEmail); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testUpdateEmail);
} }
private static void testUpdateEmail(KeycloakSession session) throws IOException { private static void testUpdateEmail(KeycloakSession session) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId()); attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -675,7 +673,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.getAttribute("email").getPermissions().setEdit(Set.of(ROLE_USER, ROLE_ADMIN)); config.getAttribute("email").getPermissions().setEdit(Set.of(ROLE_USER, ROLE_ADMIN));
// configure email r/w for user // configure email r/w for user
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes); UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create(); UserModel user = profile.create();
@ -703,7 +701,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testDoNotUpdateUndefinedAttributes); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testDoNotUpdateUndefinedAttributes);
} }
private static void testDoNotUpdateUndefinedAttributes(KeycloakSession session) throws IOException { private static void testDoNotUpdateUndefinedAttributes(KeycloakSession session) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId()); attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -719,7 +717,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addOrReplaceAttribute(new UPAttribute("department", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("department", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
config.addOrReplaceAttribute(new UPAttribute("phone", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("phone", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes); UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create(); UserModel user = profile.create();
@ -735,7 +733,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertThat(attributesUpdated, containsInAnyOrder("department", "address", "phone")); assertThat(attributesUpdated, containsInAnyOrder("department", "address", "phone"));
config.removeAttribute("address"); config.removeAttribute("address");
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
attributesUpdated.clear(); attributesUpdated.clear();
attributes.remove("address"); attributes.remove("address");
attributes.put("department", "foo"); attributes.put("department", "foo");
@ -746,7 +744,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertTrue(user.getAttributes().containsKey("address")); assertTrue(user.getAttributes().containsKey("address"));
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
attributes.put("department", "foo"); attributes.put("department", "foo");
attributes.put("phone", "foo"); attributes.put("phone", "foo");
attributes.put("address", "bar"); attributes.put("address", "bar");
@ -794,12 +792,10 @@ public class UserProfileTest extends AbstractUserProfileTest {
} }
private static void testInvalidConfiguration(KeycloakSession session) { private static void testInvalidConfiguration(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session);
try { try {
provider.setConfiguration("{\"validateConfigAttribute\": true}"); setConfiguration(session, "{\"validateConfigAttribute\": true}");
fail("Should fail validation"); fail("Should fail validation");
} catch (ComponentValidationException ve) { } catch (RuntimeException ve) {
// OK // OK
} }
@ -810,7 +806,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testResetConfiguration); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testResetConfiguration);
} }
private static void testResetConfiguration(KeycloakSession session) throws IOException { private static void testResetConfiguration(KeycloakSession session) {
setConfiguration(session, null); setConfiguration(session, null);
assertFalse(getComponentModel(session).isPresent()); assertFalse(getComponentModel(session).isPresent());
} }
@ -870,7 +866,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomValidationForUsername); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomValidationForUsername);
} }
private static void testCustomValidationForUsername(KeycloakSession session) throws IOException { private static void testCustomValidationForUsername(KeycloakSession session) {
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute(UserModel.USERNAME); UPAttribute attribute = new UPAttribute(UserModel.USERNAME);
@ -883,7 +879,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addOrReplaceAttribute(attribute); config.addOrReplaceAttribute(attribute);
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -925,7 +921,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveDefaultValidationFromUsername); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveDefaultValidationFromUsername);
} }
private static void testRemoveDefaultValidationFromUsername(KeycloakSession session) throws IOException { private static void testRemoveDefaultValidationFromUsername(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
// reset configuration to default // reset configuration to default
@ -956,7 +952,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
} }
} }
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes); profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
@ -968,7 +964,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testOptionalAttributes); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testOptionalAttributes);
} }
private static void testOptionalAttributes(KeycloakSession session) throws IOException { private static void testOptionalAttributes(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute(); UPAttribute attribute = new UPAttribute();
@ -983,7 +979,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attribute.addValidation(LengthValidator.ID, validatorConfig); attribute.addValidation(LengthValidator.ID, validatorConfig);
config.addOrReplaceAttribute(attribute); config.addOrReplaceAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1026,7 +1022,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomAttributeRequired); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomAttributeRequired);
} }
private static void testCustomAttributeRequired(KeycloakSession session) throws IOException { private static void testCustomAttributeRequired(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute(); UPAttribute attribute = new UPAttribute();
@ -1049,7 +1045,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addOrReplaceAttribute(attribute); config.addOrReplaceAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1092,7 +1088,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomAttributeOptional); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomAttributeOptional);
} }
private static void testCustomAttributeOptional(KeycloakSession session) throws IOException { private static void testCustomAttributeOptional(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute(); UPAttribute attribute = new UPAttribute();
@ -1105,7 +1101,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addOrReplaceAttribute(attribute); config.addOrReplaceAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, "user"); attributes.put(UserModel.USERNAME, "user");
@ -1144,11 +1140,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRequiredIfUser); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRequiredIfUser);
} }
private static void testRequiredIfUser(KeycloakSession session) throws IOException { private static void testRequiredIfUser(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(ROLE_USER), Set.of()))); config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(ROLE_USER), Set.of())));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1192,11 +1188,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRequiredIfAdmin); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRequiredIfAdmin);
} }
private static void testRequiredIfAdmin(KeycloakSession session) throws IOException { private static void testRequiredIfAdmin(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)), new UPAttributeRequired(Set.of(ROLE_ADMIN), Set.of()))); config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)), new UPAttributeRequired(Set.of(ROLE_ADMIN), Set.of())));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1231,11 +1227,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testNoValidationsIfUserReadOnly); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testNoValidationsIfUserReadOnly);
} }
private static void testNoValidationsIfUserReadOnly(KeycloakSession session) throws IOException { private static void testNoValidationsIfUserReadOnly(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)), new UPAttributeRequired())); config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1264,11 +1260,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testNoValidationsIfAdminReadOnly); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testNoValidationsIfAdminReadOnly);
} }
private static void testNoValidationsIfAdminReadOnly(KeycloakSession session) throws IOException { private static void testNoValidationsIfAdminReadOnly(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired())); config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1293,12 +1289,12 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testIgnoreReadOnlyAttribute); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testIgnoreReadOnlyAttribute);
} }
private static void testIgnoreReadOnlyAttribute(KeycloakSession session) throws IOException { private static void testIgnoreReadOnlyAttribute(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(ROLE_ADMIN), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(ROLE_USER), Set.of()))); config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(ROLE_ADMIN), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(ROLE_USER), Set.of())));
config.addOrReplaceAttribute(new UPAttribute(UserModel.FIRST_NAME, new UPAttributePermissions(Set.of(ROLE_ADMIN), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(ROLE_USER), Set.of()))); config.addOrReplaceAttribute(new UPAttribute(UserModel.FIRST_NAME, new UPAttributePermissions(Set.of(ROLE_ADMIN), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(ROLE_USER), Set.of())));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1343,7 +1339,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadOnlyInternalAttributeValidation); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadOnlyInternalAttributeValidation);
} }
private static void testReadOnlyInternalAttributeValidation(KeycloakSession session) throws IOException { private static void testReadOnlyInternalAttributeValidation(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
UserModel maria = session.users().addUser(realm, "maria"); UserModel maria = session.users().addUser(realm, "maria");
@ -1369,11 +1365,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRequiredByClientScope); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRequiredByClientScope);
} }
private static void testRequiredByClientScope(KeycloakSession session) throws IOException { private static void testRequiredByClientScope(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(), Set.of("client-a")))); config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired(Set.of(), Set.of("client-a"))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1438,14 +1434,14 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testConfigurationInvalidScope); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testConfigurationInvalidScope);
} }
private static void testConfigurationInvalidScope(KeycloakSession session) throws IOException { private static void testConfigurationInvalidScope(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)),
new UPAttributeRequired(Set.of(), Set.of("invalid")), new UPAttributeSelector(Set.of("invalid")))); new UPAttributeRequired(Set.of(), Set.of("invalid")), new UPAttributeSelector(Set.of("invalid"))));
try { try {
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Assert.fail("Expected to fail due to invalid client scope"); Assert.fail("Expected to fail due to invalid client scope");
} catch (ComponentValidationException cve) { } catch (ComponentValidationException cve) {
//ignore //ignore
@ -1457,7 +1453,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testUsernameAndEmailPermissionNotSetIfEmpty); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testUsernameAndEmailPermissionNotSetIfEmpty);
} }
private static void testUsernameAndEmailPermissionNotSetIfEmpty(KeycloakSession session) throws IOException { private static void testUsernameAndEmailPermissionNotSetIfEmpty(KeycloakSession session){
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = provider.getConfiguration(); UPConfig config = provider.getConfiguration();
@ -1467,7 +1463,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
} }
} }
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
RealmModel realm = session.getContext().getRealm(); RealmModel realm = session.getContext().getRealm();
String username = "profiled-user-profile"; String username = "profiled-user-profile";
@ -1491,7 +1487,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testDoNotRemoveAttributes); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testDoNotRemoveAttributes);
} }
private static void testDoNotRemoveAttributes(KeycloakSession session) throws IOException { private static void testDoNotRemoveAttributes(KeycloakSession session) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId()); attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -1507,7 +1503,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addOrReplaceAttribute(new UPAttribute("foo", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("foo", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN))));
config.addOrReplaceAttribute(new UPAttribute("email", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("email", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.USER_API, attributes); UserProfile profile = provider.create(UserProfileContext.USER_API, attributes);
UserModel user = profile.create(); UserModel user = profile.create();
@ -1546,7 +1542,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertNull(userAttributes.getFirst("foo")); assertNull(userAttributes.getFirst("foo"));
config.addOrReplaceAttribute(new UPAttribute("test-attribute", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)))); config.addOrReplaceAttribute(new UPAttribute("test-attribute", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
attributes.remove("test-attribute"); attributes.remove("test-attribute");
profile = provider.create(UserProfileContext.USER_API, attributes, user); profile = provider.create(UserProfileContext.USER_API, attributes, user);
profile.update(true); profile.update(true);
@ -1557,7 +1553,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertEquals("Test Value", userAttributes.getFirst("test-attribute")); assertEquals("Test Value", userAttributes.getFirst("test-attribute"));
config.addOrReplaceAttribute(new UPAttribute("test-attribute", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("test-attribute", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
attributes.remove("test-attribute"); attributes.remove("test-attribute");
profile = provider.create(UserProfileContext.USER_API, attributes, user); profile = provider.create(UserProfileContext.USER_API, attributes, user);
profile.update(true); profile.update(true);
@ -1573,7 +1569,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveEmptyRootAttribute); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveEmptyRootAttribute);
} }
private static void testRemoveEmptyRootAttribute(KeycloakSession session) throws IOException { private static void testRemoveEmptyRootAttribute(KeycloakSession session) {
Map<String, List<String>> attributes = new HashMap<>(); Map<String, List<String>> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, List.of(org.keycloak.models.utils.KeycloakModelUtils.generateId())); attributes.put(UserModel.USERNAME, List.of(org.keycloak.models.utils.KeycloakModelUtils.generateId()));
@ -1587,7 +1583,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.addOrReplaceAttribute(new UPAttribute(UserModel.FIRST_NAME, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER)))); config.addOrReplaceAttribute(new UPAttribute(UserModel.FIRST_NAME, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER))));
config.addOrReplaceAttribute(new UPAttribute(UserModel.LAST_NAME, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER)))); config.addOrReplaceAttribute(new UPAttribute(UserModel.LAST_NAME, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER))));
config.addOrReplaceAttribute(new UPAttribute(UserModel.EMAIL, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER)))); config.addOrReplaceAttribute(new UPAttribute(UserModel.EMAIL, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
UserProfile profile = provider.create(UserProfileContext.USER_API, attributes); UserProfile profile = provider.create(UserProfileContext.USER_API, attributes);
UserModel user = profile.create(); UserModel user = profile.create();
@ -1620,14 +1616,14 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveOptionalAttributesFromDefaultConfigIfNotSet); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveOptionalAttributesFromDefaultConfigIfNotSet);
} }
private static void testRemoveOptionalAttributesFromDefaultConfigIfNotSet(KeycloakSession session) throws IOException { private static void testRemoveOptionalAttributesFromDefaultConfigIfNotSet(KeycloakSession session) {
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("foo")); config.addOrReplaceAttribute(new UPAttribute("foo"));
config.removeAttribute(UserModel.FIRST_NAME); config.removeAttribute(UserModel.FIRST_NAME);
config.removeAttribute(UserModel.LAST_NAME); config.removeAttribute(UserModel.LAST_NAME);
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1647,7 +1643,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
UPAttribute lastName = new UPAttribute(); UPAttribute lastName = new UPAttribute();
lastName.setName(UserModel.LAST_NAME); lastName.setName(UserModel.LAST_NAME);
config.addOrReplaceAttribute(lastName); config.addOrReplaceAttribute(lastName);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user); profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
assertTrue(profile.getAttributes().contains(UserModel.FIRST_NAME)); assertTrue(profile.getAttributes().contains(UserModel.FIRST_NAME));
assertTrue(profile.getAttributes().contains(UserModel.LAST_NAME)); assertTrue(profile.getAttributes().contains(UserModel.LAST_NAME));
@ -1658,11 +1654,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testUnmanagedPolicy); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testUnmanagedPolicy);
} }
private static void testUnmanagedPolicy(KeycloakSession session) throws IOException { private static void testUnmanagedPolicy(KeycloakSession session) {
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("bar", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN)))); config.addOrReplaceAttribute(new UPAttribute("bar", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN))));
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
// can't create attribute if policy is disabled // can't create attribute if policy is disabled
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
@ -1678,27 +1674,27 @@ public class UserProfileTest extends AbstractUserProfileTest {
profile = provider.create(UserProfileContext.USER_API, attributes, user); profile = provider.create(UserProfileContext.USER_API, attributes, user);
assertFalse(profile.getAttributes().contains("foo")); assertFalse(profile.getAttributes().contains("foo"));
config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_EDIT); config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_EDIT);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.USER_API, attributes, user); profile = provider.create(UserProfileContext.USER_API, attributes, user);
assertTrue(profile.getAttributes().contains("foo")); assertTrue(profile.getAttributes().contains("foo"));
assertFalse(profile.getAttributes().isReadOnly("foo")); assertFalse(profile.getAttributes().isReadOnly("foo"));
// user already set with an unmanaged attribute, and it should be visible if policy is adminView but read-only // user already set with an unmanaged attribute, and it should be visible if policy is adminView but read-only
config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_VIEW); config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_VIEW);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.USER_API, attributes, user); profile = provider.create(UserProfileContext.USER_API, attributes, user);
assertTrue(profile.getAttributes().contains("foo")); assertTrue(profile.getAttributes().contains("foo"));
assertTrue(profile.getAttributes().isReadOnly("foo")); assertTrue(profile.getAttributes().isReadOnly("foo"));
// user already set with an unmanaged attribute, but it is not available to user-facing contexts // user already set with an unmanaged attribute, but it is not available to user-facing contexts
config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_VIEW); config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_VIEW);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user); profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
assertFalse(profile.getAttributes().contains("foo")); assertFalse(profile.getAttributes().contains("foo"));
// user already set with an unmanaged attribute, and it is available to all contexts // user already set with an unmanaged attribute, and it is available to all contexts
config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ENABLED); config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ENABLED);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user); profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
assertTrue(profile.getAttributes().contains("foo")); assertTrue(profile.getAttributes().contains("foo"));
assertFalse(profile.getAttributes().isReadOnly("foo")); assertFalse(profile.getAttributes().isReadOnly("foo"));
@ -1712,10 +1708,10 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testOptionalRootAttributesAsUnmanagedAttribute); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testOptionalRootAttributesAsUnmanagedAttribute);
} }
private static void testOptionalRootAttributesAsUnmanagedAttribute(KeycloakSession session) throws IOException { private static void testOptionalRootAttributesAsUnmanagedAttribute(KeycloakSession session) {
UPConfig config = parseDefaultConfig(); UPConfig config = parseDefaultConfig();
UserProfileProvider provider = getUserProfileProvider(session); UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
Map<String, String> rawAttributes = new HashMap<>(); Map<String, String> rawAttributes = new HashMap<>();
rawAttributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org"); rawAttributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org");
rawAttributes.put(UserModel.EMAIL, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org"); rawAttributes.put(UserModel.EMAIL, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org");
@ -1732,7 +1728,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
config.removeAttribute(UserModel.FIRST_NAME); config.removeAttribute(UserModel.FIRST_NAME);
config.removeAttribute(UserModel.LAST_NAME); config.removeAttribute(UserModel.LAST_NAME);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.USER_API, user); profile = provider.create(UserProfileContext.USER_API, user);
Attributes attributes = profile.getAttributes(); Attributes attributes = profile.getAttributes();
assertNull(attributes.getFirst(UserModel.FIRST_NAME)); assertNull(attributes.getFirst(UserModel.FIRST_NAME));
@ -1745,7 +1741,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
rawAttributes.put(UserModel.FIRST_NAME, "firstName"); rawAttributes.put(UserModel.FIRST_NAME, "firstName");
rawAttributes.put(UserModel.LAST_NAME, "lastName"); rawAttributes.put(UserModel.LAST_NAME, "lastName");
config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_EDIT); config.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_EDIT);
provider.setConfiguration(JsonSerialization.writeValueAsString(config)); provider.setConfiguration(config);
profile = provider.create(UserProfileContext.USER_API, user); profile = provider.create(UserProfileContext.USER_API, user);
attributes = profile.getAttributes(); attributes = profile.getAttributes();
assertEquals(rawAttributes.get(UserModel.FIRST_NAME), attributes.getFirst(UserModel.FIRST_NAME)); assertEquals(rawAttributes.get(UserModel.FIRST_NAME), attributes.getFirst(UserModel.FIRST_NAME));