The username in account is required and don't change when email as username is enabled

Closes #23976
This commit is contained in:
Pedro Igor 2023-10-16 08:34:07 -03:00
parent dfe64f6271
commit e91a0afca2
6 changed files with 64 additions and 26 deletions

View file

@ -183,7 +183,6 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
RealmModel realm = session.getContext().getRealm();
if (UserModel.USERNAME.equals(name)
&& UserProfileContext.USER_API.equals(context)
&& realm.isRegistrationEmailAsUsername()) {
continue;
}

View file

@ -82,17 +82,10 @@ public abstract class AbstractUserProfileProvider<U extends UserProfileProvider>
return !realm.isRegistrationEmailAsUsername();
}
if (USER_API.equals(c.getContext())) {
if (realm.isRegistrationEmailAsUsername()) {
return false;
}
if (isNewUser(c)) {
// when creating a user the username is always editable
return true;
}
}
return realm.isEditUsernameAllowed();
}

View file

@ -58,10 +58,8 @@ public class LegacyAttributes extends DefaultAttributes {
if (UserProfileContext.IDP_REVIEW.equals(context)) {
return false;
}
if (UserProfileContext.USER_API.equals(context)) {
if (realm.isRegistrationEmailAsUsername()) {
return false;
}
return true;
}
return !realm.isEditUsernameAllowed();
}
@ -94,9 +92,14 @@ public class LegacyAttributes extends DefaultAttributes {
@Override
public Map<String, List<String>> getWritable() {
Map<String, List<String>> attributes = new HashMap<>(this);
RealmModel realm = session.getContext().getRealm();
for (String name : nameSet()) {
if (isReadOnly(name)) {
if (UserModel.USERNAME.equals(name)
&& realm.isRegistrationEmailAsUsername()) {
continue;
}
attributes.remove(name);
}
}

View file

@ -147,8 +147,9 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
user = getUser();
if (isDeclarativeUserProfile()) {
assertNotNull(user.getUserProfileMetadata());
// username is read-only and is the same as email, but email is writable
assertUserProfileAttributeMetadata(user, "username", "${username}", true, true);
// username is read-only, not required, and is the same as email
// but email is writable
assertUserProfileAttributeMetadata(user, "username", "${username}", false, true);
assertUserProfileAttributeMetadata(user, "email", "${email}", true, false);
}
user.setUsername("should-be-the-email");
@ -164,7 +165,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
if (isDeclarativeUserProfile()) {
assertNotNull(user.getUserProfileMetadata());
// username is read-only and is the same as email, but email is read-only
assertUserProfileAttributeMetadata(user, "username", "${username}", true, true);
assertUserProfileAttributeMetadata(user, "username", "${username}", false, true);
assertUserProfileAttributeMetadata(user, "email", "${email}", true, true);
}
user.setUsername("should-be-the-email");
@ -189,8 +190,8 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
user = getUser();
user.setEmail("should-not-change@keycloak.org");
user = updateAndGet(user);
assertEquals("different-than-email", user.getUsername());
assertEquals("user@keycloak.org", user.getEmail());
assertEquals(user.getEmail(), user.getUsername());
} finally {
realmRep.setRegistrationEmailAsUsername(registrationEmailAsUsername);
realmRep.setEditUsernameAllowed(editUsernameAllowed);

View file

@ -102,7 +102,7 @@ public class AccountRestServiceWithUserProfileTest extends AccountRestServiceTes
@Test
@Override
public void testEditUsernameAllowed() throws IOException {
super.testEditUsernameAllowed();
setUserProfileConfiguration(UP_CONFIG_FOR_METADATA);
UserRepresentation user = getUser();

View file

@ -596,14 +596,59 @@ public class UserTest extends AbstractAdminTest {
@Test
public void createUserWithEmailAsUsername() {
switchRegistrationEmailAsUsername(true);
RealmRepresentation realmRep = realm.toRepresentation();
Boolean registrationEmailAsUsername = realmRep.isRegistrationEmailAsUsername();
Boolean editUsernameAllowed = realmRep.isEditUsernameAllowed();
getCleanup().addCleanup(() -> {
realmRep.setRegistrationEmailAsUsername(registrationEmailAsUsername);
realm.update(realmRep);
});
getCleanup().addCleanup(() -> {
realmRep.setEditUsernameAllowed(editUsernameAllowed);
realm.update(realmRep);
});
switchRegistrationEmailAsUsername(true);
switchEditUsernameAllowedOn(false);
String id = createUser();
UserResource user = realm.users().get(id);
UserRepresentation userRep = user.toRepresentation();
assertEquals("user1@localhost", userRep.getUsername());
assertEquals("user1@localhost", userRep.getEmail());
assertEquals(userRep.getEmail(), userRep.getUsername());
deleteUser(id);
switchRegistrationEmailAsUsername(true);
switchEditUsernameAllowedOn(true);
id = createUser();
user = realm.users().get(id);
userRep = user.toRepresentation();
assertEquals("user1@localhost", userRep.getEmail());
assertEquals(userRep.getEmail(), userRep.getUsername());
deleteUser(id);
switchRegistrationEmailAsUsername(false);
switchEditUsernameAllowedOn(true);
id = createUser();
user = realm.users().get(id);
userRep = user.toRepresentation();
assertEquals("user1", userRep.getUsername());
assertEquals("user1@localhost", userRep.getEmail());
deleteUser(id);
switchRegistrationEmailAsUsername(false);
switchEditUsernameAllowedOn(false);
id = createUser();
user = realm.users().get(id);
userRep = user.toRepresentation();
assertEquals("user1", userRep.getUsername());
assertEquals("user1@localhost", userRep.getEmail());
}
private void deleteUser(String id) {
try (Response response = realm.users().delete(id)) {
assertEquals(204, response.getStatus());
}
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userResourcePath(id), ResourceType.USER);
}
@Test
@ -1343,10 +1388,7 @@ public class UserTest extends AbstractAdminTest {
@Test
public void delete() {
String userId = createUser();
try (Response response = realm.users().delete(userId)) {
assertEquals(204, response.getStatus());
}
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userResourcePath(userId), ResourceType.USER);
deleteUser(userId);
}
@Test