Internal read-only attributes have precedence over unmanaged attribute policy

Closes #30240

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2024-06-18 12:49:47 -03:00 committed by Alexander Schwartz
parent 9a0fcf5982
commit 57139cbefc
2 changed files with 31 additions and 4 deletions

View file

@ -94,14 +94,14 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
@Override @Override
public boolean isReadOnly(String name) { public boolean isReadOnly(String name) {
if (!isManagedAttribute(name)) {
return !isAllowEditUnmanagedAttribute();
}
if (isReadOnlyFromMetadata(name) || isReadOnlyInternalAttribute(name)) { if (isReadOnlyFromMetadata(name) || isReadOnlyInternalAttribute(name)) {
return true; return true;
} }
if (!isManagedAttribute(name)) {
return !isAllowEditUnmanagedAttribute();
}
return getMetadata(name) == null; return getMetadata(name) == null;
} }

View file

@ -38,6 +38,7 @@ import org.keycloak.representations.idm.ErrorRepresentation;
import org.keycloak.representations.userprofile.config.UPAttribute; import org.keycloak.representations.userprofile.config.UPAttribute;
import org.keycloak.representations.userprofile.config.UPAttributePermissions; import org.keycloak.representations.userprofile.config.UPAttributePermissions;
import org.keycloak.representations.userprofile.config.UPConfig; import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;
import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.broker.util.SimpleHttpDefault; import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
@ -47,6 +48,7 @@ import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
/** /**
@ -144,6 +146,31 @@ public class AccountRestServiceReadOnlyAttributesTest extends AbstractRestServic
testAccountUpdateAttributeExpectSuccess("deniedSomeAdmin"); testAccountUpdateAttributeExpectSuccess("deniedSomeAdmin");
} }
@Test
public void testUpdateProfileCannotUpdateReadOnlyAttributesUnmanagedEnabled() throws IOException {
UPConfig configuration = testRealm().users().userProfile().getConfiguration();
UnmanagedAttributePolicy unmanagedAttributePolicy = configuration.getUnmanagedAttributePolicy();
configuration.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ENABLED);
getCleanup().addCleanup(() -> {
configuration.setUnmanagedAttributePolicy(unmanagedAttributePolicy);
testRealm().users().userProfile().update(configuration);
});
testRealm().users().userProfile().update(configuration);
UserRepresentation user = SimpleHttpDefault.doGet(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).asJson(UserRepresentation.class);
UserResource adminUserResource = ApiUtil.findUserByUsernameId(testRealm(), user.getUsername());
org.keycloak.representations.idm.UserRepresentation adminUserRep = adminUserResource.toRepresentation();
adminUserRep.singleAttribute("deniedFoo", "foo");
adminUserResource.update(adminUserRep);
adminUserResource = ApiUtil.findUserByUsernameId(testRealm(), user.getUsername());
adminUserRep = adminUserResource.toRepresentation();
assertEquals("foo", adminUserRep.getAttributes().get("deniedFoo").get(0));
assertNull(user.getAttributes());
updateAndGet(user);
adminUserResource = ApiUtil.findUserByUsernameId(testRealm(), user.getUsername());
adminUserRep = adminUserResource.toRepresentation();
assertEquals("foo", adminUserRep.getAttributes().get("deniedFoo").get(0));
}
private void testAccountUpdateAttributeExpectFailure(String attrName) throws IOException { private void testAccountUpdateAttributeExpectFailure(String attrName) throws IOException {
testAccountUpdateAttributeExpectFailure(attrName, false); testAccountUpdateAttributeExpectFailure(attrName, false);
} }