Allow updating email when email as username is set and edit username disabed

#23438
This commit is contained in:
Pedro Igor 2023-09-22 18:12:35 -03:00
parent 159a94ad5f
commit 741f76887c
5 changed files with 67 additions and 5 deletions

View file

@ -180,6 +180,13 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
for (String name : nameSet()) { for (String name : nameSet()) {
AttributeMetadata metadata = getMetadata(name); AttributeMetadata metadata = getMetadata(name);
RealmModel realm = session.getContext().getRealm();
if (UserModel.USERNAME.equals(name)
&& UserProfileContext.USER_API.equals(context)
&& realm.isRegistrationEmailAsUsername()) {
continue;
}
if (metadata == null || !metadata.canEdit(createAttributeContext(metadata))) { if (metadata == null || !metadata.canEdit(createAttributeContext(metadata))) {
attributes.remove(name); attributes.remove(name);

View file

@ -83,6 +83,12 @@ public abstract class AbstractUserProfileProvider<U extends UserProfileProvider>
return !realm.isRegistrationEmailAsUsername(); return !realm.isRegistrationEmailAsUsername();
} }
if (USER_API.equals(c.getContext())) {
if (realm.isRegistrationEmailAsUsername()) {
return false;
}
}
return realm.isEditUsernameAllowed(); return realm.isEditUsernameAllowed();
} }
@ -114,6 +120,12 @@ public abstract class AbstractUserProfileProvider<U extends UserProfileProvider>
return true; return true;
} }
if (USER_API.equals(c.getContext())) {
if (realm.isRegistrationEmailAsUsername()) {
return true;
}
}
if (Profile.isFeatureEnabled(Feature.UPDATE_EMAIL)) { if (Profile.isFeatureEnabled(Feature.UPDATE_EMAIL)) {
return !(UPDATE_PROFILE.equals(c.getContext()) || ACCOUNT.equals(c.getContext())); return !(UPDATE_PROFILE.equals(c.getContext()) || ACCOUNT.equals(c.getContext()));
} }

View file

@ -58,6 +58,11 @@ public class LegacyAttributes extends DefaultAttributes {
if (UserProfileContext.IDP_REVIEW.equals(context)) { if (UserProfileContext.IDP_REVIEW.equals(context)) {
return false; return false;
} }
if (UserProfileContext.USER_API.equals(context)) {
if (realm.isRegistrationEmailAsUsername()) {
return false;
}
}
return !realm.isEditUsernameAllowed(); return !realm.isEditUsernameAllowed();
} }
@ -65,7 +70,8 @@ public class LegacyAttributes extends DefaultAttributes {
if (isServiceAccountUser()) { if (isServiceAccountUser()) {
return false; return false;
} }
if (UserProfileContext.IDP_REVIEW.equals(context)) { if (UserProfileContext.IDP_REVIEW.equals(context)
|| UserProfileContext.USER_API.equals(context)) {
return false; return false;
} }
if (realm.isRegistrationEmailAsUsername() && !realm.isEditUsernameAllowed()) { if (realm.isRegistrationEmailAsUsername() && !realm.isEditUsernameAllowed()) {

View file

@ -2376,7 +2376,8 @@ public class UserTest extends AbstractAdminTest {
updateUser(user, userRep); updateUser(user, userRep);
userRep = realm.users().get(id).toRepresentation(); userRep = realm.users().get(id).toRepresentation();
assertEquals("user1@localhost", userRep.getUsername()); assertEquals("user11@localhost", userRep.getUsername());
assertEquals("user11@localhost", userRep.getEmail());
} }
@Test @Test
@ -2396,6 +2397,7 @@ public class UserTest extends AbstractAdminTest {
userRep = realm.users().get(id).toRepresentation(); userRep = realm.users().get(id).toRepresentation();
assertEquals("user11@localhost", userRep.getUsername()); assertEquals("user11@localhost", userRep.getUsername());
assertEquals("user11@localhost", userRep.getEmail());
} }
@Test @Test
@ -2914,7 +2916,7 @@ public class UserTest extends AbstractAdminTest {
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM); assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
} }
private void switchRegistrationEmailAsUsername(boolean enable) { protected void switchRegistrationEmailAsUsername(boolean enable) {
RealmRepresentation rep = realm.toRepresentation(); RealmRepresentation rep = realm.toRepresentation();
rep.setRegistrationEmailAsUsername(enable); rep.setRegistrationEmailAsUsername(enable);
realm.update(rep); realm.update(rep);

View file

@ -17,17 +17,18 @@
package org.keycloak.testsuite.admin; package org.keycloak.testsuite.admin;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Profile.Feature; import org.keycloak.common.Profile.Feature;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.UserProfileAttributeMetadata; import org.keycloak.representations.idm.UserProfileAttributeMetadata;
import org.keycloak.representations.idm.UserProfileMetadata; import org.keycloak.representations.idm.UserProfileMetadata;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
@ -74,6 +75,40 @@ public class UserTestWithUserProfile extends UserTest {
} }
} }
@Test
public void testUsernameReadOnlyIfEmailAsUsernameEnabled() {
switchRegistrationEmailAsUsername(true);
getCleanup().addCleanup(() -> switchRegistrationEmailAsUsername(false));
String userId = createUser("user-metadata", "user-metadata@keycloak.org");
UserRepresentation user = realm.users().get(userId).toRepresentation(true);
UserProfileMetadata metadata = user.getUserProfileMetadata();
assertNotNull(metadata);
UserProfileAttributeMetadata username = getAttributeMetadata(metadata, UserModel.USERNAME);
assertNotNull(username);
assertTrue(username.isReadOnly());
UserProfileAttributeMetadata email = getAttributeMetadata(metadata, UserModel.EMAIL);
assertNotNull(email);
assertFalse(email.isReadOnly());
}
@Test
public void testEmailNotReadOnlyIfEmailAsUsernameEnabledAndEditUsernameDisabled() {
switchRegistrationEmailAsUsername(true);
getCleanup().addCleanup(() -> switchRegistrationEmailAsUsername(false));
RealmRepresentation rep = realm.toRepresentation();
assertFalse(rep.isEditUsernameAllowed());
String userId = createUser("user-metadata", "user-metadata@keycloak.org");
UserRepresentation user = realm.users().get(userId).toRepresentation(true);
UserProfileMetadata metadata = user.getUserProfileMetadata();
assertNotNull(metadata);
UserProfileAttributeMetadata username = getAttributeMetadata(metadata, UserModel.USERNAME);
assertNotNull(username);
assertTrue(username.isReadOnly());
UserProfileAttributeMetadata email = getAttributeMetadata(metadata, UserModel.EMAIL);
assertNotNull(email);
assertFalse(email.isReadOnly());
}
@Nullable @Nullable
private static UserProfileAttributeMetadata getAttributeMetadata(UserProfileMetadata metadata, String name) { private static UserProfileAttributeMetadata getAttributeMetadata(UserProfileMetadata metadata, String name) {
UserProfileAttributeMetadata attrMetadata = null; UserProfileAttributeMetadata attrMetadata = null;