[KEYCLOAK-18916] - Do not consider empty values when checking read-only attributes

This commit is contained in:
Pedro Igor 2021-07-28 18:28:23 -03:00 committed by Stian Thorgersen
parent 32f2f095fe
commit ff70e2e04b
2 changed files with 42 additions and 1 deletions

View file

@ -16,6 +16,8 @@
*/
package org.keycloak.userprofile.validator;
import static org.keycloak.validate.Validators.notBlankValidator;
import java.util.List;
import java.util.stream.Collectors;
@ -26,6 +28,7 @@ import org.keycloak.validate.SimpleValidator;
import org.keycloak.validate.ValidationContext;
import org.keycloak.validate.ValidationError;
import org.keycloak.validate.ValidatorConfig;
import org.keycloak.validate.Validators;
/**
* A validator that fails when the attribute is marked as read only and its value has changed.
@ -62,8 +65,10 @@ public class ImmutableAttributeValidator implements SimpleValidator {
List<String> values = (List<String>) input;
if (!(currentValue.containsAll(values) && currentValue.size() == values.size())) {
if (currentValue.isEmpty() && !notBlankValidator().validate(values).isValid()) {
return context;
}
context.addError(new ValidationError(ID, inputHint, DEFAULT_ERROR_MESSAGE));
return context;
}
return context;

View file

@ -12,11 +12,13 @@ import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER
import javax.ws.rs.core.Response;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.common.Profile;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
@ -104,6 +106,40 @@ public class DeclarativeUserTest extends AbstractAdminTest {
assertTrue(attributes.containsKey("custom-hidden"));
}
@Test
public void testUpdateUnsetAttributeWithEmptyValue() {
setUserProfileConfiguration(this.realm, "{\"attributes\": ["
+ "{\"name\": \"username\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"firstName\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"email\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"lastName\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"attr1\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"attr2\"}]}");
UserRepresentation user1 = new UserRepresentation();
user1.setUsername("user1");
// set an attribute to later remove it from the configuration
user1.singleAttribute("attr1", "some-value");
String user1Id = createUser(user1);
// remove the attr1 attribute from the configuration
setUserProfileConfiguration(this.realm, "{\"attributes\": ["
+ "{\"name\": \"username\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"firstName\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"email\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"lastName\", " + PERMISSIONS_ALL + "},"
+ "{\"name\": \"attr2\"}]}");
UserResource userResource = realm.users().get(user1Id);
user1 = userResource.toRepresentation();
Map<String, List<String>> attributes = user1.getAttributes();
attributes.put("attr2", Collections.singletonList(""));
// should be able to update the user when a read-only attribute has an empty or null value
userResource.update(user1);
attributes.put("attr2", null);
userResource.update(user1);
}
private String createUser(UserRepresentation userRep) {
Response response = realm.users().create(userRep);
String createdId = ApiUtil.getCreatedId(response);