diff --git a/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeGeneralSettings.tsx b/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeGeneralSettings.tsx index 3134fa30c6e..dafa333d330 100644 --- a/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeGeneralSettings.tsx +++ b/js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeGeneralSettings.tsx @@ -100,6 +100,8 @@ export const AttributeGeneralSettings = () => { )); + const ROOT_ATTRIBUTE = [...USERNAME_EMAIL, "firstName", "lastName"]; + return ( @@ -139,11 +141,13 @@ export const AttributeGeneralSettings = () => { label={t("multivalued")} labelIcon={t("multivaluedHelp")} /> - + {!ROOT_ATTRIBUTE.includes(attributeName) && ( + + )} errors = new ArrayList<>(); - List attributeNames = attributes.stream().map(UPAttribute::getName).collect(Collectors.toList()); + List attributeNames = attributes.stream().map(UPAttribute::getName).toList(); for (String name : Arrays.asList(UserModel.USERNAME, UserModel.EMAIL)) { if (!attributeNames.contains(name)) { @@ -185,15 +186,7 @@ public class UPConfigUtils { } if (attributeConfig.getValidations() != null) { attributeConfig.getValidations().forEach((validator, validatorConfig) -> validateValidationConfig(session, validator, validatorConfig, attributeName, errors)); - - if (attributeConfig.getDefaultValue() != null) { - attributeConfig.getValidations().forEach((validator, validatorConfig) -> { - ValidationContext context = Validators.validator(session, validator).validate(attributeConfig.getDefaultValue(), attributeName, ValidatorConfig.configFromMap(validatorConfig)); - if (!context.isValid()) { - errors.add("Default value is invalid"); - } - }); - } + validateDefaultValue(session, attributeConfig, errors); } if (attributeConfig.getPermissions() != null) { if (attributeConfig.getPermissions().getView() != null) { @@ -222,6 +215,27 @@ public class UPConfigUtils { } } + private static void validateDefaultValue(KeycloakSession session, UPAttribute attributeConfig, List errors) { + String defaultValue = attributeConfig.getDefaultValue(); + + if (defaultValue == null) { + return; + } + + String attributeName = attributeConfig.getName(); + + if (isRootAttribute(attributeName)) { + errors.add("Default value not supported for attribute '" + attributeName + "'"); + } else { + attributeConfig.getValidations().forEach((validator, validatorConfig) -> { + ValidationContext context = Validators.validator(session, validator).validate(defaultValue, attributeName, ValidatorConfig.configFromMap(validatorConfig)); + if (!context.isValid()) { + errors.add("Default value for attribute '" + attributeName + "' is invalid"); + } + }); + } + } + private static void validateAnnotations(Map annotations, List errors, String attributeName) { if (annotations.containsKey("inputOptions") && !(annotations.get("inputOptions") instanceof List)) { errors.add(new StringBuilder("Annotation 'inputOptions' configured for attribute '").append(attributeName).append("' must be an array of values!'").toString()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/user/profile/UserProfileTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/user/profile/UserProfileTest.java index 38de84e4128..bc1486a63c4 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/user/profile/UserProfileTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/user/profile/UserProfileTest.java @@ -81,6 +81,7 @@ import org.keycloak.userprofile.UserProfile; import org.keycloak.userprofile.UserProfileConstants; import org.keycloak.userprofile.UserProfileContext; import org.keycloak.userprofile.UserProfileProvider; +import org.keycloak.userprofile.UserProfileUtil; import org.keycloak.userprofile.ValidationException; import org.keycloak.userprofile.config.UPConfigUtils; import org.keycloak.userprofile.validator.MultiValueValidator; @@ -2400,6 +2401,7 @@ public class UserProfileTest extends AbstractUserProfileTest { public void testDefaultValue() { getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testInvalidConfigDefaultValue); getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testDefaultValue); + getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testNoDefaultValueForRootAttributes); } private static void testInvalidConfigDefaultValue(KeycloakSession session) { @@ -2438,6 +2440,27 @@ public class UserProfileTest extends AbstractUserProfileTest { assertThat(actualValue, Matchers.equalTo(expectedValue)); } + private static void testNoDefaultValueForRootAttributes(KeycloakSession session) { + UserProfileProvider provider = getUserProfileProvider(session); + UPConfig upConfig = UPConfigUtils.parseSystemDefaultConfig(); + upConfig.getAttribute(UserModel.USERNAME).setDefaultValue("def"); + upConfig.getAttribute(UserModel.EMAIL).setDefaultValue("def"); + upConfig.getAttribute(UserModel.FIRST_NAME).setDefaultValue("def"); + upConfig.getAttribute(UserModel.LAST_NAME).setDefaultValue("def"); + + try { + provider.setConfiguration(upConfig); + fail("Should fail validation for default value"); + } catch (ComponentValidationException cve) { + String message = cve.getMessage(); + for (String attributeName : List.of(UserModel.USERNAME, UserModel.EMAIL, UserModel.FIRST_NAME, UserModel.LAST_NAME)) { + if (UserProfileUtil.isRootAttribute(attributeName)) { + assertThat(message, Matchers.containsString("Default value not supported for attribute '" + attributeName + "'")); + } + } + } + } + private static void testMultivalued(KeycloakSession session) { UserProfileProvider provider = getUserProfileProvider(session); UPConfig upConfig = UPConfigUtils.parseSystemDefaultConfig();