From 493145b4ced04bd6da06758c59aada407b4eaee2 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Thu, 7 May 2026 10:32:00 -0300 Subject: [PATCH] Align the format of the annotation kc.scim.schema.attribute to how SCIM defines custom schema attributes Closes #48632 Signed-off-by: Pedro Igor --- .../attribute/AttributeScimSettings.tsx | 14 +-- .../resource/schema/attribute/Attribute.java | 13 ++- .../schema/SchemaResourceTypeProvider.java | 4 +- .../tests/scim/tck/AbstractScimTest.java | 39 +++++++-- .../keycloak/tests/scim/tck/FilterTest.java | 21 +---- .../keycloak/tests/scim/tck/SchemaTest.java | 51 +++++++---- .../org/keycloak/tests/scim/tck/UserTest.java | 86 +++++-------------- 7 files changed, 105 insertions(+), 123 deletions(-) diff --git a/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeScimSettings.tsx b/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeScimSettings.tsx index 339ce3a8b9b..285b63f771b 100644 --- a/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeScimSettings.tsx +++ b/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeScimSettings.tsx @@ -25,13 +25,13 @@ const SCIM_CORE_ATTRIBUTES = [ ]; const SCIM_ENTERPRISE_ATTRIBUTES = [ - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.employeeNumber", - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.costCenter", - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.organization", - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.division", - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.department", - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.manager.value", - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.manager.displayName", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:costCenter", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:organization", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:division", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.value", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:manager.displayName", ]; type ScimAttributeGroup = { diff --git a/scim/core/src/main/java/org/keycloak/scim/resource/schema/attribute/Attribute.java b/scim/core/src/main/java/org/keycloak/scim/resource/schema/attribute/Attribute.java index 0c97352112a..556bf7ce5be 100644 --- a/scim/core/src/main/java/org/keycloak/scim/resource/schema/attribute/Attribute.java +++ b/scim/core/src/main/java/org/keycloak/scim/resource/schema/attribute/Attribute.java @@ -38,25 +38,24 @@ public class Attribute { return null; } - return name.substring(0, schemaSeparator) + ":" + getResourceType(name); + return name.substring(0, schemaSeparator); } public static String getResourceType(String name) { requireNonNull(name, "name is required"); - int schemaSeparator = name.lastIndexOf(':'); + String schema = getSchema(name); - if (schemaSeparator == -1) { + if (schema == null) { return null; } - String resourceType = name.substring(schemaSeparator + 1); - int fieldSeparator = resourceType.indexOf('.'); + int resourceTypeSeparator = schema.lastIndexOf(':'); - if (fieldSeparator == -1) { + if (resourceTypeSeparator == -1) { return null; } - return resourceType.substring(0, fieldSeparator); + return schema.substring(resourceTypeSeparator + 1); } public static String getSimpleName(String name) { diff --git a/scim/model/src/main/java/org/keycloak/scim/model/schema/SchemaResourceTypeProvider.java b/scim/model/src/main/java/org/keycloak/scim/model/schema/SchemaResourceTypeProvider.java index 1cda8727b47..4ceed96243e 100644 --- a/scim/model/src/main/java/org/keycloak/scim/model/schema/SchemaResourceTypeProvider.java +++ b/scim/model/src/main/java/org/keycloak/scim/model/schema/SchemaResourceTypeProvider.java @@ -155,7 +155,9 @@ public class SchemaResourceTypeProvider implements ScimResourceTypeProvider attributes = rep.getAttributes(); + + if (!modelSchema.isInternal() && !attributes.isEmpty()) { schemas.put(modelSchema.getId(), rep); } } diff --git a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/AbstractScimTest.java b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/AbstractScimTest.java index 8d9675c3c75..bfd73144cc6 100644 --- a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/AbstractScimTest.java +++ b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/AbstractScimTest.java @@ -11,8 +11,12 @@ package org.keycloak.tests.scim.tck; import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; import org.keycloak.representations.userprofile.config.UPAttribute; +import org.keycloak.representations.userprofile.config.UPAttributePermissions; import org.keycloak.representations.userprofile.config.UPConfig; import org.keycloak.scim.client.ScimClient; import org.keycloak.testframework.annotations.InjectAdminEvents; @@ -20,6 +24,7 @@ import org.keycloak.testframework.annotations.InjectRealm; import org.keycloak.testframework.events.AdminEvents; import org.keycloak.testframework.realm.ManagedRealm; import org.keycloak.testframework.scim.client.annotations.InjectScimClient; +import org.keycloak.userprofile.config.UPConfigUtils; import static org.keycloak.scim.model.user.AbstractUserModelSchema.ANNOTATION_SCIM_SCHEMA_ATTRIBUTE; import static org.keycloak.scim.resource.Scim.ENTERPRISE_USER_SCHEMA; @@ -37,22 +42,42 @@ public abstract class AbstractScimTest { protected void addEnterpriseUserUserProfileAttributes() { UPConfig configuration = realm.admin().users().userProfile().getConfiguration(); + UPConfig originalConfig = configuration.clone(); + realm.cleanup().add(realm -> realm.users().userProfile().update(originalConfig)); configuration.addOrReplaceAttribute(new UPAttribute("department", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".department"))); + ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ":department"))); configuration.addOrReplaceAttribute(new UPAttribute("division", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".division"))); + ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ":division"))); configuration.addOrReplaceAttribute(new UPAttribute("costCenter", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".costCenter"))); + ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ":costCenter"))); configuration.addOrReplaceAttribute(new UPAttribute("employeeNumber", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".employeeNumber"))); + ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ":employeeNumber"))); configuration.addOrReplaceAttribute(new UPAttribute("organization", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".organization"))); + ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ":organization"))); configuration.addOrReplaceAttribute(new UPAttribute("manager", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".manager.value"))); + ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ":manager.value"))); configuration.addOrReplaceAttribute(new UPAttribute("managerName", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".manager.displayName"))); + ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ":manager.displayName"))); realm.admin().users().userProfile().update(configuration); } + protected UPAttribute addOrReplaceUPAttribute(String name) { + return addOrReplaceUPAttribute(null, name); + } + + protected UPAttribute addOrReplaceUPAttribute(String customSchema, String name) { + UPConfig upConfig = realm.admin().users().userProfile().getConfiguration(); + UPAttribute upAttribute = new UPAttribute("scim." + name, Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, Optional.ofNullable(customSchema).map(new Function() { + @Override + public String apply(String s) { + return s + ":"; + } + }).orElse("") + name)); + upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); + upConfig.addOrReplaceAttribute(upAttribute); + realm.admin().users().userProfile().update(upConfig); + adminEvents.clear(); + return upAttribute; + } } diff --git a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/FilterTest.java b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/FilterTest.java index c839b33dcec..1a9e379ba10 100644 --- a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/FilterTest.java +++ b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/FilterTest.java @@ -4,7 +4,6 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import org.keycloak.models.UserModel; @@ -24,7 +23,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.keycloak.scim.model.user.AbstractUserModelSchema.ANNOTATION_SCIM_SCHEMA_ATTRIBUTE; import static org.keycloak.scim.resource.Scim.ENTERPRISE_USER_SCHEMA; import static org.hamcrest.MatcherAssert.assertThat; @@ -617,24 +615,7 @@ public class FilterTest extends AbstractScimTest { @Test public void testSearchEnterpriseUsers() { - UPConfig configuration = realm.admin().users().userProfile().getConfiguration(); - - // update user profile configuration - configuration.addOrReplaceAttribute(new UPAttribute("department", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".department"))); - configuration.addOrReplaceAttribute(new UPAttribute("division", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".division"))); - configuration.addOrReplaceAttribute(new UPAttribute("costCenter", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".costCenter"))); - configuration.addOrReplaceAttribute(new UPAttribute("employeeNumber", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".employeeNumber"))); - configuration.addOrReplaceAttribute(new UPAttribute("organization", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".organization"))); - configuration.addOrReplaceAttribute(new UPAttribute("manager", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".manager.value"))); - configuration.addOrReplaceAttribute(new UPAttribute("managerName", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".manager.displayName"))); - realm.admin().users().userProfile().update(configuration); + addEnterpriseUserUserProfileAttributes(); User user1 = createEnterpriseUser("user1", "Engineering", "E1234", "Bruce Wayne"); User user2 = createEnterpriseUser("user2", "QE", "E7763", "Lucius Fox"); diff --git a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/SchemaTest.java b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/SchemaTest.java index 007d4224f7f..639fbd38560 100644 --- a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/SchemaTest.java +++ b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/SchemaTest.java @@ -1,23 +1,16 @@ package org.keycloak.tests.scim.tck; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import org.keycloak.representations.userprofile.config.UPAttribute; -import org.keycloak.representations.userprofile.config.UPAttributePermissions; -import org.keycloak.representations.userprofile.config.UPConfig; import org.keycloak.scim.protocol.response.ListResponse; import org.keycloak.scim.resource.Scim; import org.keycloak.scim.resource.schema.Schema; import org.keycloak.testframework.annotations.KeycloakIntegrationTest; -import org.keycloak.userprofile.config.UPConfigUtils; import org.junit.jupiter.api.Test; -import static org.keycloak.scim.model.user.AbstractUserModelSchema.ANNOTATION_SCIM_SCHEMA_ATTRIBUTE; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -29,6 +22,7 @@ public class SchemaTest extends AbstractScimTest { @Test public void testGetAllSchemas() { + addEnterpriseUserUserProfileAttributes(); String customSchema = "urn:my:params:scim:schemas:extension:custom:1.0:User"; addOrReplaceUPAttribute(customSchema, "myattribute"); @@ -50,6 +44,40 @@ public class SchemaTest extends AbstractScimTest { assertTrue(schemaIds.contains(customSchema)); } + @Test + public void testSchemasWithNoAttributesNotReturned() { + // Extension schemas with no user profile attributes mapped should not be returned + // (e.g., EnterpriseUser schema when no UP attributes have the kc.scim.schema.attribute annotation) + ListResponse response = client.schemas().getAll(); + + assertNotNull(response); + assertNotNull(response.getResources()); + + List schemaIds = response.getResources().stream() + .map(Schema::getId) + .toList(); + + // Core schemas are always present regardless of attributes + assertTrue(schemaIds.contains(Scim.USER_CORE_SCHEMA)); + assertTrue(schemaIds.contains(Scim.GROUP_CORE_SCHEMA)); + + // EnterpriseUser schema should not be listed when no UP attributes are mapped to it + assertFalse(schemaIds.contains(Scim.ENTERPRISE_USER_SCHEMA), + "Schemas with no attributes should not be returned from the /Schemas endpoint"); + + // Only core schemas should be returned + assertEquals(2, response.getTotalResults()); + + // After adding enterprise user attributes, the schema should appear + addEnterpriseUserUserProfileAttributes(); + response = client.schemas().getAll(); + schemaIds = response.getResources().stream() + .map(Schema::getId) + .toList(); + assertTrue(schemaIds.contains(Scim.ENTERPRISE_USER_SCHEMA), + "Schema should be returned once attributes are mapped to it"); + } + @Test public void testGetUserCoreSchema() { Schema schema = client.schemas().get(Scim.USER_CORE_SCHEMA); @@ -212,6 +240,7 @@ public class SchemaTest extends AbstractScimTest { assertEquals(1, nameCount, "name attribute should appear exactly once"); // Verify EnterpriseUser manager appears only once + addEnterpriseUserUserProfileAttributes(); Schema enterpriseSchema = client.schemas().get(Scim.ENTERPRISE_USER_SCHEMA); List enterpriseNames = enterpriseSchema.getAttributes().stream() .map(Schema.Attribute::getName) @@ -247,12 +276,4 @@ public class SchemaTest extends AbstractScimTest { assertEquals(multiValued, subAttribute.getMultiValued(), subAttribute.getName() + " sub-attribute multiValued"); assertEquals(mutability, subAttribute.getMutability(), subAttribute.getName() + " sub-attribute mutability"); } - - private void addOrReplaceUPAttribute(String customSchema, String name) { - UPConfig upConfig = realm.admin().users().userProfile().getConfiguration(); - UPAttribute upAttribute = new UPAttribute("scim" + name, Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, customSchema + "." + name)); - upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); - upConfig.addOrReplaceAttribute(upAttribute); - realm.admin().users().userProfile().update(upConfig); - } } diff --git a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/UserTest.java b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/UserTest.java index 02f1580cd74..acb861a9c91 100644 --- a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/UserTest.java +++ b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/UserTest.java @@ -394,15 +394,9 @@ public class UserTest extends AbstractScimTest { @Test public void testPatchAdd() { User expected = client.users().create(createUser()); - UPConfig configuration = realm.admin().users().userProfile().getConfiguration(); - configuration.addOrReplaceAttribute(new UPAttribute("middleName", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.middleName"))); - configuration.addOrReplaceAttribute(new UPAttribute("honorificPrefix", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.honorificPrefix"))); - configuration.addOrReplaceAttribute(new UPAttribute("honorificSuffix", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.honorificSuffix"))); - realm.admin().users().userProfile().update(configuration); - adminEvents.clear(); + addOrReplaceUPAttribute("name.middleName"); + addOrReplaceUPAttribute("name.honorificPrefix"); + addOrReplaceUPAttribute("name.honorificSuffix"); // patch multiple attributes in a single request client.users().patch(expected.getId(), PatchRequest.create() @@ -499,9 +493,7 @@ public class UserTest extends AbstractScimTest { assertRootAttributes(actual, expected); // patch an attribute from an extension schema - configuration.addOrReplaceAttribute(new UPAttribute("employeeNumber", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".employeeNumber"))); - realm.admin().users().userProfile().update(configuration); + addOrReplaceUPAttribute(ENTERPRISE_USER_SCHEMA, "employeeNumber"); assertNull(actual.getEnterpriseUser()); client.users().patch(expected.getId(), PatchRequest.create() .add(ENTERPRISE_USER_SCHEMA + ":" + "employeeNumber", "1234") @@ -537,9 +529,7 @@ public class UserTest extends AbstractScimTest { assertEquals("321", actual.getEnterpriseUser().getEmployeeNumber()); assertEquals("Amanda", actual.getFirstName()); - configuration.addOrReplaceAttribute(new UPAttribute("managerId", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".manager.value"))); - realm.admin().users().userProfile().update(configuration); + addOrReplaceUPAttribute(ENTERPRISE_USER_SCHEMA, "manager.value"); // patch a sub attribute of a complex attribute using a direct path client.users().patch(expected.getId(), PatchRequest.create() .add("{\"name.givenName\": \"Alice\", \"" + ENTERPRISE_USER_SCHEMA + ":manager\": \"321\"}}") @@ -563,14 +553,9 @@ public class UserTest extends AbstractScimTest { @Test public void testPatchReplace() { User expected = client.users().create(createUser()); - UPConfig configuration = realm.admin().users().userProfile().getConfiguration(); - configuration.addOrReplaceAttribute(new UPAttribute("middleName", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.middleName"))); - configuration.addOrReplaceAttribute(new UPAttribute("honorificPrefix", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.honorificPrefix"))); - configuration.addOrReplaceAttribute(new UPAttribute("honorificSuffix", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.honorificSuffix"))); - realm.admin().users().userProfile().update(configuration); + addOrReplaceUPAttribute("name.middleName"); + addOrReplaceUPAttribute("name.honorificPrefix"); + addOrReplaceUPAttribute("name.honorificSuffix"); // patch multiple attributes in a single request client.users().patch(expected.getId(), PatchRequest.create() @@ -654,9 +639,7 @@ public class UserTest extends AbstractScimTest { assertRootAttributes(actual, expected); // patch an attribute from an extension schema - configuration.addOrReplaceAttribute(new UPAttribute("employeeNumber", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".employeeNumber"))); - realm.admin().users().userProfile().update(configuration); + addOrReplaceUPAttribute(ENTERPRISE_USER_SCHEMA, "employeeNumber"); assertNull(actual.getEnterpriseUser()); client.users().patch(expected.getId(), PatchRequest.create() .replace(ENTERPRISE_USER_SCHEMA + ":" + "employeeNumber", "1234") @@ -689,14 +672,9 @@ public class UserTest extends AbstractScimTest { @Test public void testPatchRemove() { User expected = client.users().create(createUser()); - UPConfig configuration = realm.admin().users().userProfile().getConfiguration(); - configuration.addOrReplaceAttribute(new UPAttribute("middleName", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.middleName"))); - configuration.addOrReplaceAttribute(new UPAttribute("honorificPrefix", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.honorificPrefix"))); - configuration.addOrReplaceAttribute(new UPAttribute("honorificSuffix", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, "name.honorificSuffix"))); - realm.admin().users().userProfile().update(configuration); + addOrReplaceUPAttribute("name.middleName"); + addOrReplaceUPAttribute("name.honorificPrefix"); + addOrReplaceUPAttribute("name.honorificSuffix"); // patch multiple attributes in a single request client.users().patch(expected.getId(), PatchRequest.create() @@ -723,11 +701,8 @@ public class UserTest extends AbstractScimTest { assertRootAttributes(actual, expected); assertNull(actual.getEnterpriseUser()); - configuration.addOrReplaceAttribute(new UPAttribute("employeeNumber", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".employeeNumber"))); - configuration.addOrReplaceAttribute(new UPAttribute("costCenter", Map.of( - ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, ENTERPRISE_USER_SCHEMA + ".costCenter"))); - realm.admin().users().userProfile().update(configuration); + addOrReplaceUPAttribute(ENTERPRISE_USER_SCHEMA, "employeeNumber"); + addOrReplaceUPAttribute(ENTERPRISE_USER_SCHEMA, "costCenter"); client.users().patch(expected.getId(), PatchRequest.create() .add(ENTERPRISE_USER_SCHEMA + ":" + "employeeNumber", "1234") .add(ENTERPRISE_USER_SCHEMA + ":" + "costCenter", "5678") @@ -1089,18 +1064,11 @@ public class UserTest extends AbstractScimTest { @Test public void testCreateCustomAttribute() { - UPConfig upConfig = realm.admin().users().userProfile().getConfiguration(); String fooSchema = "urn:my:params:scim:schemas:extension:foo:1.0:User"; - UPAttribute upAttribute = new UPAttribute("keycloak.team", Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, fooSchema + ".memberOf")); - upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); - upConfig.addOrReplaceAttribute(upAttribute); - realm.admin().users().userProfile().update(upConfig); + addOrReplaceUPAttribute(fooSchema, "memberOf"); String barSchema = "urn:my:params:scim:schemas:extension:bar:1.0:User"; - upAttribute = new UPAttribute("keycloak.area", Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, barSchema + ".myattribute")); - upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); - upConfig.addOrReplaceAttribute(upAttribute); - realm.admin().users().userProfile().update(upConfig); + addOrReplaceUPAttribute(barSchema, "myattribute"); User user = new User(); @@ -1146,20 +1114,13 @@ public class UserTest extends AbstractScimTest { } // adds a user profile attribute - UPConfig upConfig = realm.admin().users().userProfile().getConfiguration(); - UPAttribute upAttribute = new UPAttribute("keycloak.team", Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, KEYCLOAK_USER_SCHEMA + ".memberOf")); - upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); - upConfig.addOrReplaceAttribute(upAttribute); - realm.admin().users().userProfile().update(upConfig); + UPAttribute upAttribute = addOrReplaceUPAttribute(KEYCLOAK_USER_SCHEMA, "memberOf"); existing = realm.admin().users().get(existing.getId()).toRepresentation(); existing.singleAttribute(upAttribute.getName(), "core-iam"); realm.admin().users().get(existing.getId()).update(existing); String customSchema = "urn:my:params:scim:schemas:extension:custom:1.0:User"; - upAttribute = new UPAttribute("keycloak.area", Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, customSchema + ".myattribute")); - upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); - upConfig.addOrReplaceAttribute(upAttribute); - realm.admin().users().userProfile().update(upConfig); + upAttribute = addOrReplaceUPAttribute(customSchema, "myattribute"); existing = realm.admin().users().get(existing.getId()).toRepresentation(); existing.singleAttribute(upAttribute.getName(), "myvalue"); realm.admin().users().get(existing.getId()).update(existing); @@ -1222,17 +1183,10 @@ public class UserTest extends AbstractScimTest { @Test public void testPatchCustomAttribute() { - UPConfig upConfig = realm.admin().users().userProfile().getConfiguration(); - UPAttribute upAttribute = new UPAttribute("keycloak.team", Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, KEYCLOAK_USER_SCHEMA + ".memberOf")); - upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); - upConfig.addOrReplaceAttribute(upAttribute); - realm.admin().users().userProfile().update(upConfig); + addOrReplaceUPAttribute(KEYCLOAK_USER_SCHEMA, "memberOf"); String customSchema = "urn:my:params:scim:schemas:extension:custom:1.0:User"; - upAttribute = new UPAttribute("keycloak.area", Map.of(ANNOTATION_SCIM_SCHEMA_ATTRIBUTE, customSchema + ".myattribute")); - upAttribute.setPermissions(new UPAttributePermissions(Set.of(UPConfigUtils.ROLE_ADMIN), Set.of(UPConfigUtils.ROLE_ADMIN))); - upConfig.addOrReplaceAttribute(upAttribute); - realm.admin().users().userProfile().update(upConfig); + addOrReplaceUPAttribute(customSchema, "myattribute"); User user = new User();