Make sure optional default attributes are removed when decorating the user-define user profile configuration

Closes #24420
This commit is contained in:
Pedro Igor 2023-10-31 11:45:28 -03:00 committed by Marek Posolda
parent e96d6b38a8
commit be65ba8689
2 changed files with 54 additions and 1 deletions

View file

@ -27,6 +27,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -448,6 +449,10 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
return UserModel.USERNAME.equals(attributeName) || UserModel.EMAIL.equals(attributeName);
}
private boolean isOptionalBuiltInAttribute(String attributeName) {
return UserModel.FIRST_NAME.equals(attributeName) || UserModel.LAST_NAME.equals(attributeName);
}
private Predicate<AttributeContext> createViewAllowedPredicate(Predicate<AttributeContext> canEdit,
Set<String> viewRoles) {
return ac -> UPConfigUtils.isRoleForContext(ac.getContext(), viewRoles) || canEdit.test(ac);
@ -521,7 +526,11 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
throw new RuntimeException("UserProfile configuration for realm '" + session.getContext().getRealm().getName() + "' is invalid: " + errors.toString());
}
for (AttributeMetadata metadata : decoratedMetadata.getAttributes()) {
Iterator<AttributeMetadata> attributes = decoratedMetadata.getAttributes().iterator();
while (attributes.hasNext()) {
AttributeMetadata metadata = attributes.next();
String attributeName = metadata.getName();
if (isBuiltInAttribute(attributeName)) {
@ -534,6 +543,10 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
// user-defined configuration will add its own validators
validators.removeIf(m -> m.getValidatorId().equals(id));
}
} else if (isOptionalBuiltInAttribute(attributeName)) {
// removes optional default attributes in favor of user-defined configuration
// make sure any attribute other than username and email are removed from the metadata
attributes.remove();
}
}

View file

@ -1665,4 +1665,44 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertNull(user.getEmail());
assertEquals(upAttributes.getFirstValue(UserModel.FIRST_NAME), attributes.get(UserModel.FIRST_NAME).get(0));
}
@Test
public void testRemoveOptionalAttributesFromDefaultConfigIfNotSet() {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testRemoveOptionalAttributesFromDefaultConfigIfNotSet);
}
private static void testRemoveOptionalAttributesFromDefaultConfigIfNotSet(KeycloakSession session) throws IOException {
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName("foo");
config.addAttribute(attribute);
UserProfileProvider provider = getUserProfileProvider(session);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org");
attributes.put(UserModel.EMAIL, org.keycloak.models.utils.KeycloakModelUtils.generateId() + "@keycloak.org");
attributes.put("foo", "foo");
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
UserModel user = profile.create();
assertFalse(profile.getAttributes().contains(UserModel.FIRST_NAME));
assertFalse(profile.getAttributes().contains(UserModel.LAST_NAME));
UPAttribute firstName = new UPAttribute();
firstName.setName(UserModel.FIRST_NAME);
config.addAttribute(firstName);
UPAttribute lastName = new UPAttribute();
lastName.setName(UserModel.LAST_NAME);
config.addAttribute(lastName);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes, user);
assertTrue(profile.getAttributes().contains(UserModel.FIRST_NAME));
assertTrue(profile.getAttributes().contains(UserModel.LAST_NAME));
}
}