Make sure username is lowercase when normalizing attributes

Closes #25173

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2023-11-30 16:46:01 -03:00 committed by Marek Posolda
parent 20e3a8e360
commit c5bcdbdc3f
4 changed files with 27 additions and 16 deletions

View file

@ -31,12 +31,11 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;
import org.keycloak.common.util.CollectionUtil;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.storage.StorageId;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
import org.keycloak.validate.ValidationContext;
@ -361,6 +360,10 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
values = (List<String>) value;
}
if (UserModel.USERNAME.equals(key) || UserModel.EMAIL.equals(key)) {
values = values.stream().map(KeycloakModelUtils::toLowerCaseSafe).collect(Collectors.toList());
}
newAttributes.put(key, Collections.unmodifiableList(values));
}
}
@ -394,7 +397,6 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
if (!email.isEmpty() && realm.isRegistrationEmailAsUsername()) {
List<String> lowerCaseEmailList = email.stream()
.filter(Objects::nonNull)
.map(String::toLowerCase)
.collect(Collectors.toList());
setUserName(newAttributes, lowerCaseEmailList);

View file

@ -121,7 +121,7 @@ public class RegisterTest extends AbstractTestRealmKeycloakTest {
assertEquals("", registerPage.getPassword());
assertEquals("", registerPage.getPasswordConfirm());
events.expectRegister("roleRichUser", "registerExistingUser@email")
events.expectRegister("rolerichuser", "registerExistingUser@email")
.removeDetail(Details.EMAIL)
.user((String) null).error("username_in_use").assertEvent();
}
@ -145,7 +145,7 @@ public class RegisterTest extends AbstractTestRealmKeycloakTest {
assertEquals("", registerPage.getPassword());
assertEquals("", registerPage.getPasswordConfirm());
events.expectRegister("registerExistingUser", "registerExistingUser@email")
events.expectRegister("registerexistinguser", "registerexistin@email")
.removeDetail(Details.EMAIL)
.user((String) null).error("email_in_use").assertEvent();
}
@ -339,7 +339,7 @@ public class RegisterTest extends AbstractTestRealmKeycloakTest {
registerPage.register("firstName", "lastName", null, "registerUserMissingEmail", "password", "password");
registerPage.assertCurrent();
assertEquals("Please specify email.", registerPage.getInputAccountErrors().getEmailError());
events.expectRegister("registerUserMissingEmail", null)
events.expectRegister("registerusermissingemail", null)
.removeDetail("email")
.error("invalid_registration").assertEvent();
}
@ -354,7 +354,7 @@ public class RegisterTest extends AbstractTestRealmKeycloakTest {
registerPage.assertCurrent();
assertEquals("registerUserInvalidEmailemail", registerPage.getEmail());
assertEquals("Invalid email address.", registerPage.getInputAccountErrors().getEmailError());
events.expectRegister("registerUserInvalidEmail", "registerUserInvalidEmailemail")
events.expectRegister("registeruserinvalidemail", "registeruserinvalidemailemail")
.error("invalid_registration").assertEvent();
}
@ -648,7 +648,7 @@ public class RegisterTest extends AbstractTestRealmKeycloakTest {
registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserInvalidEmailemail", "password", "password");
registerPage.assertCurrent();
assertEquals("Invalid email address.", registerPage.getInputAccountErrors().getEmailError());
events.expectRegister("registerUserInvalidEmailemail", "registerUserInvalidEmailemail").error("invalid_registration").assertEvent();
events.expectRegister("registeruserinvalidemailemail", "registeruserinvalidemailemail").error("invalid_registration").assertEvent();
}
}

View file

@ -223,7 +223,7 @@ public class RegisterWithUserProfileTest extends RegisterTest {
registerPage.assertCurrent();
assertEquals("Length must be between 3 and 255.", registerPage.getInputAccountErrors().getLastNameError());
events.expectRegister("registerUserInvalidLastNameLength", "registerUserInvalidLastNameLength@email")
events.expectRegister("registeruserinvalidlastnamelength", "registeruserinvalidlastnamelength@email")
.error("invalid_registration").assertEvent();
}

View file

@ -42,7 +42,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.junit.Assert;
import org.junit.ClassRule;
@ -60,14 +59,8 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
import org.keycloak.services.messages.Messages;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.ldap.idm.model.LDAPObject;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper;
import org.keycloak.testsuite.federation.ldap.LDAPTestContext;
import org.keycloak.testsuite.runonserver.RunOnServer;
import org.keycloak.testsuite.util.LDAPRule;
import org.keycloak.testsuite.util.LDAPTestUtils;
import org.keycloak.userprofile.AttributeGroupMetadata;
import org.keycloak.representations.userprofile.config.UPAttribute;
import org.keycloak.representations.userprofile.config.UPAttributePermissions;
@ -1832,4 +1825,20 @@ public class UserProfileTest extends AbstractUserProfileTest {
assertTrue(profile.getAttributes().contains("foo"));
assertFalse(profile.getAttributes().isReadOnly("foo"));
}
@Test
public void testAttributeNormalization() {
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testAttributeNormalization);
}
private static void testAttributeNormalization(KeycloakSession session) {
UserProfileProvider provider = getUserProfileProvider(session);
Map<String, String> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, "TesT");
attributes.put(UserModel.EMAIL, "TesT@TesT.org");
UserProfile profile = provider.create(UserProfileContext.USER_API, attributes);
Attributes profileAttributes = profile.getAttributes();
assertEquals(attributes.get(UserModel.USERNAME).toLowerCase(), profileAttributes.getFirstValue(UserModel.USERNAME));
assertEquals(attributes.get(UserModel.EMAIL).toLowerCase(), profileAttributes.getFirstValue(UserModel.EMAIL));
}
}