Do not allow removing username and email from user profile configuration

Closes #25147

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2023-12-08 07:45:49 -03:00 committed by Alexander Schwartz
parent 0a95159e07
commit 78ba7d4a38
17 changed files with 261 additions and 277 deletions

View file

@ -49,6 +49,26 @@ public class UPAttribute {
this.name = name != null ? name.trim() : null;
}
public UPAttribute(String name, UPGroup group) {
this(name);
this.group = group.getName();
}
public UPAttribute(String name, UPAttributePermissions permissions, UPAttributeRequired required, UPAttributeSelector selector) {
this(name);
this.permissions = permissions;
this.required = required;
this.selector = selector;
}
public UPAttribute(String name, UPAttributePermissions permissions, UPAttributeRequired required) {
this(name, permissions, required, null);
}
public UPAttribute(String name, UPAttributePermissions permissions) {
this(name, permissions, null);
}
public String getName() {
return name;
}

View file

@ -33,6 +33,15 @@ public class UPAttributePermissions {
private Set<String> view = Collections.emptySet();
private Set<String> edit = Collections.emptySet();
public UPAttributePermissions() {
// for reflection
}
public UPAttributePermissions(Set<String> view, Set<String> edit) {
this.view = view;
this.edit = edit;
}
public Set<String> getView() {
return view;
}

View file

@ -33,6 +33,15 @@ public class UPAttributeRequired {
private Set<String> roles;
private Set<String> scopes;
public UPAttributeRequired() {
// for reflection
}
public UPAttributeRequired(Set<String> roles, Set<String> scopes) {
this.roles = roles;
this.scopes = scopes;
}
/**
* Check if this config means that the attribute is ALWAYS required.
*

View file

@ -30,6 +30,14 @@ public class UPAttributeSelector {
private Set<String> scopes;
public UPAttributeSelector() {
// for reflection
}
public UPAttributeSelector(Set<String> scopes) {
this.scopes = scopes;
}
public Set<String> getScopes() {
return scopes;
}

View file

@ -50,16 +50,21 @@ public class UPConfig {
this.attributes = attributes;
}
public UPConfig addAttribute(UPAttribute attribute) {
public UPConfig addOrReplaceAttribute(UPAttribute attribute) {
if (attributes == null) {
attributes = new ArrayList<>();
}
removeAttribute(attribute.getName());
attributes.add(attribute);
return this;
}
public boolean removeAttribute(String name) {
return attributes != null && attributes.removeIf(attribute -> attribute.getName().equals(name));
}
public List<UPGroup> getGroups() {
if (groups == null) {
return Collections.emptyList();

View file

@ -33,6 +33,14 @@ public class UPGroup {
private String displayDescription;
private Map<String, Object> annotations;
public UPGroup() {
// for reflection
}
public UPGroup(String name) {
this.name = name;
}
public String getName() {
return name;
}

View file

@ -131,6 +131,8 @@ describe("User profile tabs", () => {
{
"attributes": [
{
"name": "email"{downArrow},
{
"name": "username",
"validations": {
"length": {

View file

@ -191,6 +191,7 @@ export const AttributesTab = () => {
{
title: t("delete"),
isActionable: ({ name }) => !RESTRICTED_ATTRIBUTES.includes(name!),
isDisabled: RESTRICTED_ATTRIBUTES.includes(name!),
onClick: (_key, _idx, component) => {
setAttributeToDelete(component.name);
toggleDeleteDialog();

View file

@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@ -36,6 +37,7 @@ import org.keycloak.common.util.StreamUtil;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.userprofile.config.UPAttribute;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.userprofile.UserProfileContext;
@ -128,6 +130,7 @@ public class UPConfigUtils {
if (config.getAttributes() != null) {
Set<String> attNamesCache = new HashSet<>();
config.getAttributes().forEach((attribute) -> validateAttribute(session, attribute, groups, errors, attNamesCache));
errors.addAll(validateRootAttributes(config));
} else {
errors.add("UserProfile configuration without 'attributes' section is not allowed");
}
@ -135,6 +138,25 @@ public class UPConfigUtils {
return errors;
}
private static List<String> validateRootAttributes(UPConfig config) {
List<UPAttribute> attributes = config.getAttributes();
if (attributes == null) {
return Collections.emptyList();
}
List<String> errors = new ArrayList<>();
List<String> attributeNames = attributes.stream().map(UPAttribute::getName).collect(Collectors.toList());
for (String name : Arrays.asList(UserModel.USERNAME, UserModel.EMAIL)) {
if (!attributeNames.contains(name)) {
errors.add("The attribute '" + name + "' can not be removed");
}
}
return errors;
}
/**
* Validate attribute configuration
*
@ -304,4 +326,12 @@ public class UPConfigUtils {
throw new RuntimeException("Failed to load default user profile config file", cause);
}
}
public static UPConfig parseDefaultConfig() {
try {
return JsonSerialization.readValue(readDefaultConfig(), UPConfig.class);
} catch (IOException e) {
throw new RuntimeException("Failed to parse default user profile configuration", e);
}
}
}

View file

@ -61,7 +61,7 @@ public class UserTestWithUserProfile extends UserTest {
UPConfig upConfig = realm.users().userProfile().getConfiguration();
for (String name : managedAttributes) {
upConfig.addAttribute(createAttributeMetadata(name));
upConfig.addOrReplaceAttribute(createAttributeMetadata(name));
}
VerifyProfileTest.setUserProfileConfiguration(realm, JsonSerialization.writeValueAsString(upConfig));

View file

@ -44,6 +44,7 @@ import org.keycloak.representations.userprofile.config.UPAttribute;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPGroup;
import org.keycloak.testsuite.util.JsonTestUtils;
import org.keycloak.userprofile.config.UPConfigUtils;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -66,7 +67,7 @@ public class UserProfileAdminTest extends AbstractAdminTest {
@Test
public void testSetDefaultConfig() {
UPConfig config = new UPConfig().addAttribute(new UPAttribute("test"));
UPConfig config = UPConfigUtils.parseDefaultConfig().addOrReplaceAttribute(new UPAttribute("test"));
UserProfileResource userProfile = testRealm().users().userProfile();
userProfile.update(config);
getCleanup().addCleanup(() -> testRealm().users().userProfile().update(null));

View file

@ -47,6 +47,7 @@ import org.keycloak.testsuite.runonserver.RunHelpers;
import org.keycloak.testsuite.util.JsonTestUtils;
import org.keycloak.testsuite.util.UserBuilder;
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
import org.keycloak.util.JsonSerialization;
import java.io.File;
import java.io.IOException;
@ -273,7 +274,7 @@ public class ExportImportTest extends AbstractKeycloakTest {
realmRes.update(realmRep);
//add some non-default config
VerifyProfileTest.setUserProfileConfiguration(realmRes, VerifyProfileTest.CONFIGURATION_FOR_USER_EDIT);
UPConfig persistedConfig = VerifyProfileTest.setUserProfileConfiguration(realmRes, VerifyProfileTest.CONFIGURATION_FOR_USER_EDIT);
//export
TestingExportImportResource exportImport = testingClient.testing().exportImport();
@ -297,7 +298,7 @@ public class ExportImportTest extends AbstractKeycloakTest {
MultivaluedHashMap<String, String> config = userProfileComponents.get(0).getConfig();
assertThat(config, notNullValue());
assertThat(config.size(), equalTo(1));
JsonTestUtils.assertJsonEquals(config.getFirst(DeclarativeUserProfileProvider.UP_COMPONENT_CONFIG_KEY), VerifyProfileTest.CONFIGURATION_FOR_USER_EDIT, UPConfig.class);
JsonTestUtils.assertJsonEquals(config.getFirst(DeclarativeUserProfileProvider.UP_COMPONENT_CONFIG_KEY), JsonSerialization.writeValueAsString(persistedConfig), UPConfig.class);
}
@Test

View file

@ -108,7 +108,7 @@ public class LDAPAdminRestApiWithUserProfileTest extends LDAPAdminRestApiTest {
attribute.setPermissions(permissions);
upConfig.addAttribute(attribute);
upConfig.addOrReplaceAttribute(attribute);
setUserProfileConfiguration(testRealm(), writeValueAsString(upConfig));
}

View file

@ -22,12 +22,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_ADMIN;
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_USER;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
@ -46,6 +49,9 @@ import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.userprofile.config.UPAttribute;
import org.keycloak.representations.userprofile.config.UPAttributePermissions;
import org.keycloak.representations.userprofile.config.UPAttributeRequired;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
@ -1159,7 +1165,7 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
+ "{\"name\": \"department\"," + PERMISSIONS_ALL + ", " + VALIDATIONS_LENGTH + "}"
+ "]}";
setUserProfileConfiguration(customConfig);
UPConfig persistedConfig = setUserProfileConfiguration(customConfig);
RealmResource realmRes = testRealm();
disableDynamicUserProfile(realmRes, false);
@ -1167,7 +1173,7 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
enableDynamicUserProfile(realm);
testRealm().update(realm);
JsonTestUtils.assertJsonEquals(customConfig, realmRes.users().userProfile().getConfiguration());
JsonTestUtils.assertJsonEquals(JsonSerialization.writeValueAsString(persistedConfig), realmRes.users().userProfile().getConfiguration());
}
protected UserRepresentation getUser(String userId) {
@ -1186,8 +1192,8 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
testRealm().users().get(userId).update(ur);
}
protected void setUserProfileConfiguration(String configuration) {
setUserProfileConfiguration(testRealm(), configuration);
protected UPConfig setUserProfileConfiguration(String configuration) {
return setUserProfileConfiguration(testRealm(), configuration);
}
public static void enableDynamicUserProfile(RealmRepresentation testRealm) {
@ -1214,10 +1220,27 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
}
public static void setUserProfileConfiguration(RealmResource testRealm, String configuration) {
public static UPConfig setUserProfileConfiguration(RealmResource testRealm, String configuration) {
try {
UPConfig config = configuration == null ? null : JsonSerialization.readValue(configuration, UPConfig.class);
if (config != null) {
UPAttribute username = config.getAttribute(UserModel.USERNAME);
if (username == null) {
config.addOrReplaceAttribute(new UPAttribute(UserModel.USERNAME));
}
UPAttribute email = config.getAttribute(UserModel.EMAIL);
if (email == null) {
config.addOrReplaceAttribute(new UPAttribute(UserModel.EMAIL, new UPAttributePermissions(Set.of(ROLE_USER, ROLE_ADMIN), Set.of(ROLE_USER, ROLE_ADMIN)), new UPAttributeRequired(Set.of(ROLE_USER), Set.of())));
}
}
testRealm.users().userProfile().update(config);
return config;
} catch (IOException ioe) {
throw new RuntimeException("Failed to read configuration", ioe);
}

View file

@ -104,7 +104,7 @@ public abstract class AbstractUserProfileTest extends AbstractTestRealmKeycloakT
Map<String, Object> validatorConfig = new HashMap<>();
validatorConfig.put("min", 3);
attribute.addValidation("length", validatorConfig);
config.addAttribute(attribute);
config.addOrReplaceAttribute(attribute);
}
String newConfig = JsonSerialization.writeValueAsString(config);
return newConfig;

View file

@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_ADMIN;
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_USER;
import static org.keycloak.userprofile.config.UPConfigUtils.parseDefaultConfig;
import jakarta.ws.rs.core.Response;
import java.io.IOException;
@ -58,6 +59,7 @@ import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
import org.keycloak.representations.userprofile.config.UPGroup;
import org.keycloak.services.messages.Messages;
import org.keycloak.testsuite.runonserver.RunOnServer;
import org.keycloak.testsuite.util.LDAPRule;
@ -75,7 +77,6 @@ import org.keycloak.userprofile.UserProfile;
import org.keycloak.userprofile.UserProfileContext;
import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.userprofile.ValidationException;
import org.keycloak.userprofile.config.UPConfigUtils;
import org.keycloak.userprofile.validator.UsernameIDNHomographValidator;
import org.keycloak.util.JsonSerialization;
import org.keycloak.validate.ValidationError;
@ -111,7 +112,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
@Test
public void testReadOnlyAllowed() throws Exception {
// create a user with attribute foo value 123 allowed by the profile now but disallowed later
UPConfig config = JsonSerialization.readValue("{\"attributes\": [{\"name\": \"foo\", \"permissions\": {\"edit\": [\"admin\"]}}]}", UPConfig.class);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("foo", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
RealmResource realmRes = testRealm();
realmRes.users().userProfile().update(config);
@ -131,8 +133,10 @@ public class UserProfileTest extends AbstractUserProfileTest {
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().getUserById(realm, userId);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"foo\", \"validations\": {\"length\": {\"min\": \"5\", \"max\": \"15\"}}, \"permissions\": {\"edit\": [\"admin\"]}}]}");
UPConfig upConfig = provider.getConfiguration();
upConfig.getAttribute("foo")
.setValidations(Map.of("length", Map.of("min", "5", "max", "15")));
provider.setConfiguration(JsonSerialization.writeValueAsString(upConfig));
Map<String, List<String>> attributes = new HashMap<>(user.getAttributes());
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
profile.validate();
@ -143,7 +147,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().getUserById(realm, userId);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"foo\", \"validations\": {\"length\": {\"min\": \"5\", \"max\": \"15\"}}, \"permissions\": {\"edit\": [\"admin\", \"user\"]}}]}");
UPConfig upConfig = provider.getConfiguration();
UPAttribute changedFoo = upConfig.getAttribute("foo");
changedFoo.setPermissions(new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN)));
changedFoo.setValidations(Map.of("length", Map.of("min", "5", "max", "15")));
provider.setConfiguration(JsonSerialization.writeValueAsString(upConfig));
Map<String, List<String>> attributes = new HashMap<>(user.getAttributes());
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
@ -174,7 +182,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testCustomAttributeInAnyContext);
}
private static void testCustomAttributeInAnyContext(KeycloakSession session) {
private static void testCustomAttributeInAnyContext(KeycloakSession session) throws IOException {
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, "profiled-user");
@ -183,8 +191,9 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.EMAIL, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org");
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"address\", \"required\": {}, \"permissions\": {\"edit\": [\"user\"]}}]}");
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
@ -198,10 +207,12 @@ public class UserProfileTest extends AbstractUserProfileTest {
containsInAnyOrder(UserModel.USERNAME, UserModel.EMAIL, UserModel.FIRST_NAME, UserModel.LAST_NAME, "address");
// not writable in user api, no validation should happen
profile = provider.create(UserProfileContext.USER_API, attributes);
profile.validate();
attributes.put("address", "myaddress");
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
profile.validate();
}
@ -210,7 +221,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testResolveProfile);
}
private static void testResolveProfile(KeycloakSession session) {
private static void testResolveProfile(KeycloakSession session) throws IOException {
configureAuthenticationSession(session);
Map<String, Object> attributes = new HashMap<>();
@ -221,8 +232,9 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.EMAIL, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org");
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"business.address\", \"required\": {\"scopes\": [\"customer\"]}, \"permissions\": {\"edit\": [\"user\"]}}]}");
UPConfig config = parseDefaultConfig();
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));
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
@ -346,21 +358,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
UserModel user = session.users().addUser(realm, "profiled-user");
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName("address");
UPAttributeRequired requirements = new UPAttributeRequired();
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(ROLE_USER));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user);
@ -388,15 +387,17 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testGetProfileAttributes);
}
private static void testGetProfileAttributes(KeycloakSession session) {
private static void testGetProfileAttributes(KeycloakSession session) throws IOException {
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId());
user.setFirstName("John");
user.setLastName("John");
user.setEmail(org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org");
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"address\", \"required\": {}, \"permissions\": {\"edit\": [\"user\"]}}]}");
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user);
Attributes attributes = profile.getAttributes();
@ -433,38 +434,21 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testGetProfileAttributeGroups);
}
private static void testGetProfileAttributeGroups(KeycloakSession session) {
private static void testGetProfileAttributeGroups(KeycloakSession session) throws IOException {
RealmModel realm = session.getContext().getRealm();
UserModel user = session.users().addUser(realm, org.keycloak.models.utils.KeycloakModelUtils.generateId());
UserProfileProvider provider = getUserProfileProvider(session);
String configuration = "{\n" +
" \"attributes\": [\n" +
" {\n" +
" \"name\": \"address\",\n" +
" \"group\": \"companyaddress\"\n" +
" },\n" +
" {\n" +
" \"name\": \"second\",\n" +
" \"group\": \"groupwithanno" + "\"\n" +
" }\n" +
" ],\n" +
" \"groups\": [\n" +
" {\n" +
" \"name\": \"companyaddress\",\n" +
" \"displayHeader\": \"header\",\n" +
" \"displayDescription\": \"description\"\n" +
" },\n" +
" {\n" +
" \"name\": \"groupwithanno\",\n" +
" \"annotations\": {\n" +
" \"anno1\": \"value1\",\n" +
" \"anno2\": \"value2\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}\n";
provider.setConfiguration(configuration);
UPConfig config = parseDefaultConfig();
UPGroup companyAddress = new UPGroup("companyaddress");
companyAddress.setDisplayHeader("header");
companyAddress.setDisplayDescription("description");
config.addGroup(companyAddress);
config.addOrReplaceAttribute(new UPAttribute("address", companyAddress));
UPGroup groupWithAnnotation = new UPGroup("groupwithanno");
groupWithAnnotation.setAnnotations(Map.of("anno1", "value1", "anno2", "value2"));
config.addGroup(groupWithAnnotation);
config.addOrReplaceAttribute(new UPAttribute("second", groupWithAnnotation));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, user);
Attributes attributes = profile.getAttributes();
@ -498,20 +482,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = provider.getConfiguration();
UPAttribute attribute = new UPAttribute();
attribute.setName("address");
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(new HashSet<>(Arrays.asList("admin", "user")));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
attribute = new UPAttribute();
attribute.setName("business.address");
permissions = new UPAttributePermissions();
permissions.setEdit(new HashSet<>(Arrays.asList("admin", "user")));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
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))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
@ -572,7 +544,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadonlyUpdates);
}
private static void testReadonlyUpdates(KeycloakSession session) {
private static void testReadonlyUpdates(KeycloakSession session) throws IOException {
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -583,8 +555,9 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put("department", Arrays.asList("sales"));
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": [{\"name\": \"department\", \"permissions\": {\"edit\": [\"admin\"]}}]}");
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("department", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create();
@ -625,7 +598,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testReadonlyEmailCannotBeUpdated);
}
private static void testReadonlyEmailCannotBeUpdated(KeycloakSession session) {
private static void testReadonlyEmailCannotBeUpdated(KeycloakSession session) throws IOException {
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -634,9 +607,11 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.EMAIL, "readonly@foo.bar");
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("email", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
// configure email r/o for user
provider.setConfiguration("{\"attributes\": [{\"name\": \"email\", \"permissions\": {\"edit\": [ \"admin\"]}}]}");
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create();
@ -653,15 +628,18 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.EMAIL, "cannot-change@foo.bar");
profile = provider.create(UserProfileContext.ACCOUNT, attributes, user);
try {
profile.update();
fail("Should fail since email is read only");
} catch (ValidationException ve) {
assertTrue(ve.isAttributeOnError("email"));
}
assertEquals("E-Mail address shouldn't be changed", "readonly@foo.bar", user.getEmail());
attributes.put(UserModel.EMAIL, "admin-can-change@foo.bar");
profile = provider.create(UserProfileContext.USER_API, attributes, user);
profile.update();
assertEquals("admin-can-change@foo.bar", user.getEmail());
}
@Test
@ -669,7 +647,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testUpdateEmail);
}
private static void testUpdateEmail(KeycloakSession session) {
private static void testUpdateEmail(KeycloakSession session) throws IOException {
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -678,9 +656,12 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put(UserModel.EMAIL, "canchange@foo.bar");
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig();
config.getAttribute("email").getPermissions().setEdit(Set.of(ROLE_USER, ROLE_ADMIN));
// configure email r/w for user
provider.setConfiguration("{\"attributes\": [{\"name\": \"email\", \"permissions\": {\"edit\": [ \"user\", \"admin\"]}}]}");
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create();
@ -708,7 +689,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testDoNotUpdateUndefinedAttributes);
}
private static void testDoNotUpdateUndefinedAttributes(KeycloakSession session) {
private static void testDoNotUpdateUndefinedAttributes(KeycloakSession session) throws IOException {
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -720,10 +701,12 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put("phone", Arrays.asList("fixed-phone"));
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig();
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("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
provider.setConfiguration("{\"attributes\": [{\"name\": \"department\", \"permissions\": {\"edit\": [\"admin\"]}},"
+ "{\"name\": \"phone\", \"permissions\": {\"edit\": [\"admin\"]}},"
+ "{\"name\": \"address\", \"permissions\": {\"edit\": [\"admin\"]}}]}");
UserProfile profile = provider.create(UserProfileContext.ACCOUNT, attributes);
UserModel user = profile.create();
assertThat(profile.getAttributes().nameSet(),
@ -737,8 +720,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
profile.update((attributeName, userModel, oldValue) -> assertTrue(attributesUpdated.add(attributeName)));
assertThat(attributesUpdated, containsInAnyOrder("department", "address", "phone"));
provider.setConfiguration("{\"attributes\": [{\"name\": \"department\", \"permissions\": {\"edit\": [\"admin\"]}},"
+ "{\"name\": \"phone\", \"permissions\": {\"edit\": [\"admin\"]}}]}");
config.removeAttribute("address");
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
attributesUpdated.clear();
attributes.remove("address");
attributes.put("department", "foo");
@ -748,9 +731,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertThat(attributesUpdated, containsInAnyOrder("department", "phone"));
assertTrue(user.getAttributes().containsKey("address"));
provider.setConfiguration("{\"attributes\": [{\"name\": \"department\", \"permissions\": {\"edit\": [\"admin\"]}},"
+ "{\"name\": \"phone\", \"permissions\": {\"edit\": [\"admin\"]}},"
+ "{\"name\": \"address\", \"permissions\": {\"edit\": [\"admin\"]}}]}");
config.addOrReplaceAttribute(new UPAttribute("address", new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
attributes.put("department", "foo");
attributes.put("phone", "foo");
attributes.put("address", "bar");
@ -875,10 +857,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testCustomValidationForUsername(KeycloakSession session) throws IOException {
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(UserModel.USERNAME);
UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute(UserModel.USERNAME);
Map<String, Object> validatorConfig = new HashMap<>();
@ -886,7 +866,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
attribute.addValidation(LengthValidator.ID, validatorConfig);
config.addAttribute(attribute);
config.addOrReplaceAttribute(attribute);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
@ -916,7 +896,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
provider.setConfiguration(null);
attributes.put(UserModel.USERNAME, "user");
attributes.put(UserModel.USERNAME, ROLE_USER);
attributes.put(UserModel.EMAIL, "user@keycloak.org");
attributes.put(UserModel.FIRST_NAME, "Joe");
attributes.put(UserModel.LAST_NAME, "Doe");
@ -976,18 +956,18 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testOptionalAttributes(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(UserModel.FIRST_NAME);
Map<String, Object> validatorConfig = new HashMap<>();
validatorConfig.put(LengthValidator.KEY_MAX, 4);
attribute.addValidation(LengthValidator.ID, validatorConfig);
config.addAttribute(attribute);
config.addOrReplaceAttribute(attribute);
attribute = new UPAttribute();
attribute.setName(UserModel.LAST_NAME);
attribute.addValidation(LengthValidator.ID, validatorConfig);
config.addAttribute(attribute);
config.addOrReplaceAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
@ -1034,7 +1014,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testCustomAttributeRequired(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
@ -1053,7 +1033,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
permissions.setEdit(Collections.singleton(ROLE_USER));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
config.addOrReplaceAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
@ -1100,7 +1080,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testCustomAttributeOptional(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPConfig config = parseDefaultConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
@ -1109,7 +1089,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
validatorConfig.put(LengthValidator.KEY_MIN, 4);
attribute.addValidation(LengthValidator.ID, validatorConfig);
config.addAttribute(attribute);
config.addOrReplaceAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
@ -1152,23 +1132,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testRequiredIfUser(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
requirements.setRoles(Collections.singleton(ROLE_USER));
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(ROLE_USER));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
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())));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
@ -1215,23 +1180,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testRequiredIfAdmin(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
requirements.setRoles(Collections.singleton(ROLE_ADMIN));
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(UPConfigUtils.ROLE_ADMIN));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
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())));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
@ -1269,20 +1219,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testNoValidationsIfUserReadOnly(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(UPConfigUtils.ROLE_ADMIN));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
@ -1314,20 +1252,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testNoValidationsIfAdminReadOnly(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(UPConfigUtils.ROLE_USER));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute(ATT_ADDRESS, new UPAttributePermissions(Set.of(), Set.of(ROLE_USER)), new UPAttributeRequired()));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
@ -1355,29 +1281,9 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testIgnoreReadOnlyAttribute(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute firstName = new UPAttribute();
firstName.setName(UserModel.FIRST_NAME);
UPAttribute address = new UPAttribute();
address.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
requirements.setRoles(Collections.singleton(UPConfigUtils.ROLE_USER));
address.setRequired(requirements);
firstName.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(UPConfigUtils.ROLE_USER));
permissions.setView(Collections.singleton(ROLE_ADMIN));
address.setPermissions(permissions);
firstName.setPermissions(permissions);
config.addAttribute(address);
config.addAttribute(firstName);
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(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));
Map<String, Object> attributes = new HashMap<>();
@ -1451,23 +1357,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
private static void testRequiredByClientScope(KeycloakSession session) throws IOException {
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
requirements.setScopes(Collections.singleton("client-a"));
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton("user"));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
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"))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
@ -1534,23 +1425,10 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testConfigurationInvalidScope(KeycloakSession session) throws IOException {
RealmModel realm = session.getContext().getRealm();
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
requirements.setScopes(Collections.singleton("invalid"));
attribute.setRequired(requirements);
attribute.setSelector(new UPAttributeSelector());
attribute.getSelector().setScopes(Collections.singleton("invalid"));
config.addAttribute(attribute);
UPConfig config = parseDefaultConfig();
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"))));
try {
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
@ -1599,7 +1477,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testDoNotRemoveAttributes);
}
private static void testDoNotRemoveAttributes(KeycloakSession session) {
private static void testDoNotRemoveAttributes(KeycloakSession session) throws IOException {
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId());
@ -1608,11 +1486,14 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put("foo", Arrays.asList("foo"));
UserProfileProvider provider = getUserProfileProvider(session);
UPConfig config = parseDefaultConfig();
config.removeAttribute(UserModel.FIRST_NAME);
config.removeAttribute(UserModel.LAST_NAME);
config.addOrReplaceAttribute(new UPAttribute("test-attribute", 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))));
provider.setConfiguration("{\"attributes\": ["
+ "{\"name\": \"test-attribute\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"foo\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"email\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}}]}");
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.USER_API, attributes);
UserModel user = profile.create();
@ -1650,10 +1531,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertEquals("Test Value", userAttributes.getFirstValue("test-attribute"));
assertNull(userAttributes.getFirstValue("foo"));
provider.setConfiguration("{\"attributes\": ["
+ "{\"name\": \"test-attribute\", \"permissions\": {\"edit\": [\"user\"]}},"
+ "{\"name\": \"foo\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"email\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}}]}");
config.addOrReplaceAttribute(new UPAttribute("test-attribute", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
attributes.remove("test-attribute");
profile = provider.create(UserProfileContext.USER_API, attributes, user);
profile.update(true);
@ -1663,10 +1542,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertEquals("new-email@test.com", userAttributes.getFirstValue(UserModel.EMAIL));
assertEquals("Test Value", userAttributes.getFirstValue("test-attribute"));
provider.setConfiguration("{\"attributes\": ["
+ "{\"name\": \"test-attribute\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"foo\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"email\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}}]}");
config.addOrReplaceAttribute(new UPAttribute("test-attribute", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
attributes.remove("test-attribute");
profile = provider.create(UserProfileContext.USER_API, attributes, user);
profile.update(true);
@ -1682,7 +1559,7 @@ public class UserProfileTest extends AbstractUserProfileTest {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveEmptyRootAttribute);
}
private static void testRemoveEmptyRootAttribute(KeycloakSession session) {
private static void testRemoveEmptyRootAttribute(KeycloakSession session) throws IOException {
Map<String, List<String>> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, List.of(org.keycloak.models.utils.KeycloakModelUtils.generateId()));
@ -1691,12 +1568,12 @@ public class UserProfileTest extends AbstractUserProfileTest {
attributes.put("test-attribute", List.of(""));
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration("{\"attributes\": ["
+ "{\"name\": \"test-attribute\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"firstName\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"lastName\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}},"
+ "{\"name\": \"email\", \"permissions\": {\"edit\": [\"admin\", \"user\"]}}]}");
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("test-attribute", 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.EMAIL, new UPAttributePermissions(Set.of(), Set.of(ROLE_ADMIN, ROLE_USER))));
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
UserProfile profile = provider.create(UserProfileContext.USER_API, attributes);
UserModel user = profile.create();
@ -1730,12 +1607,10 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testRemoveOptionalAttributesFromDefaultConfigIfNotSet(KeycloakSession session) throws IOException {
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName("foo");
config.addAttribute(attribute);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("foo"));
config.removeAttribute(UserModel.FIRST_NAME);
config.removeAttribute(UserModel.LAST_NAME);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
@ -1754,10 +1629,10 @@ public class UserProfileTest extends AbstractUserProfileTest {
UPAttribute firstName = new UPAttribute();
firstName.setName(UserModel.FIRST_NAME);
config.addAttribute(firstName);
config.addOrReplaceAttribute(firstName);
UPAttribute lastName = new UPAttribute();
lastName.setName(UserModel.LAST_NAME);
config.addAttribute(lastName);
config.addOrReplaceAttribute(lastName);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
assertTrue(profile.getAttributes().contains(UserModel.FIRST_NAME));
@ -1770,16 +1645,8 @@ public class UserProfileTest extends AbstractUserProfileTest {
}
private static void testUnmanagedPolicy(KeycloakSession session) throws IOException {
UPConfig config = new UPConfig();
UPAttribute bar = new UPAttribute("bar");
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Set.of("user", "admin"));
bar.setPermissions(permissions);
config.addAttribute(bar);
UPConfig config = parseDefaultConfig();
config.addOrReplaceAttribute(new UPAttribute("bar", new UPAttributePermissions(Set.of(), Set.of(ROLE_USER, ROLE_ADMIN))));
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));

View file

@ -198,7 +198,7 @@ public class UPConfigParserTest extends AbstractTestRealmKeycloakTest {
UPConfig config = loadValidConfig();
//we run this test without KeycloakSession so validator configs are not validated here
UPAttribute attConfig = config.getAttributes().get(1);
UPAttribute attConfig = config.getAttributes().get(2);
attConfig.setName(null);
List<String> errors = validate(session, config);
@ -209,7 +209,7 @@ public class UPConfigParserTest extends AbstractTestRealmKeycloakTest {
Assert.assertEquals(1, errors.size());
// duplicate attribute name
attConfig.setName("firstName");
attConfig.setName("lastName");
errors = validate(session, config);
Assert.assertEquals(1, errors.size());