mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
Do not lower-case username and email if users are not imported from LDAP
Closes #43621 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
2b785425fa
commit
6527b139dc
@ -100,6 +100,12 @@ The `Use Truststore SPI` configuration property is deprecated. It should normal
|
||||
|
||||
If you set the *Import Users* option, the LDAP Provider handles importing LDAP users into the {project_name} local database. The first time a user logs in or is returned as part of a user query (e.g. using the search field in the admin console), the LDAP provider imports the LDAP user into the {project_name} database. During authentication, the LDAP password is validated.
|
||||
|
||||
By default, {project_name} does not support the username and email attributes with case-sensitive values when storing users to the local database. The value for these attributes will be stored in lower-case in the local database.
|
||||
However, if the *Import Users* option is disabled, {project_name} will not lower-case the username and email attributes when querying users from LDAP.
|
||||
This behavior allows you to use case-sensitive usernames and emails when *Import Users* is disabled. Note that this behavior applies only to username and email attributes. Other attributes remain case-sensitive.
|
||||
|
||||
It is recommended to not use case-sensitive usernames and emails when using LDAP with {project_name}, as some features in {project_name} may not work correctly with case-sensitive usernames and emails.
|
||||
|
||||
If you want to sync all LDAP users into the {project_name} database, configure and enable the *Sync Settings* on the LDAP provider configuration page.
|
||||
|
||||
Two types of synchronization exist:
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
|
||||
package org.keycloak.storage.ldap;
|
||||
|
||||
import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED;
|
||||
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.models.LDAPConstants;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
@ -284,6 +286,10 @@ public class LDAPConfig {
|
||||
return LDAPConstants.VENDOR_NOVELL_EDIRECTORY.equalsIgnoreCase(getVendor());
|
||||
}
|
||||
|
||||
public boolean isImportEnabled() {
|
||||
return Boolean.parseBoolean(config.getFirstOrDefault(IMPORT_ENABLED, Boolean.TRUE.toString())) ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return config.hashCode() * 13 + binaryAttributeNames.hashCode();
|
||||
|
||||
@ -186,7 +186,11 @@ public class LDAPUtils {
|
||||
config.getUsernameLdapAttribute() + ", user DN: " + ldapUser.getDn() + ", attributes from LDAP: " + ldapUser.getAttributes());
|
||||
}
|
||||
|
||||
return Optional.of(ldapUsername).map(String::toLowerCase).orElse(null);
|
||||
if (config.isImportEnabled()) {
|
||||
return Optional.of(ldapUsername).map(String::toLowerCase).orElse(null);
|
||||
}
|
||||
|
||||
return ldapUsername;
|
||||
}
|
||||
|
||||
public static void checkUuid(LDAPObject ldapUser, LDAPConfig config) {
|
||||
|
||||
@ -295,7 +295,7 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
|
||||
public String getUsername() {
|
||||
if (UserModel.USERNAME.equals(userModelAttrName)) {
|
||||
return ofNullable(ldapUser.getAttributeAsString(ldapAttrName))
|
||||
.map(String::toLowerCase)
|
||||
.map(this::toLowerCaseIfImportEnabled)
|
||||
.orElse(null);
|
||||
}
|
||||
return super.getUsername();
|
||||
@ -305,7 +305,7 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
|
||||
public String getEmail() {
|
||||
if (UserModel.EMAIL.equals(userModelAttrName)) {
|
||||
return ofNullable(ldapUser.getAttributeAsString(ldapAttrName))
|
||||
.map(String::toLowerCase)
|
||||
.map(this::toLowerCaseIfImportEnabled)
|
||||
.orElse(null);
|
||||
}
|
||||
return super.getEmail();
|
||||
@ -347,6 +347,12 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
|
||||
return true;
|
||||
}
|
||||
|
||||
private String toLowerCaseIfImportEnabled(String value) {
|
||||
if (getLdapProvider().getModel().isImportEnabled()) {
|
||||
return value.toLowerCase();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
} else if (isBinaryAttribute) {
|
||||
|
||||
@ -529,7 +529,7 @@ searchClientByName=Search client by name
|
||||
loginTimeout=Login timeout
|
||||
attributeName=Attribute [Name]
|
||||
updateError=Could not update the provider {{error}}
|
||||
importUsersHelp=If true, LDAP users will be imported into the Keycloak database and synced by the configured sync policies.
|
||||
importUsersHelp=If true, LDAP users will be imported into the local database and synced by the configured sync policies. If import is enabled, the username and email attributes will be stored in the local database using case-insensitivity values, in lower-case. If disabled, those attributes will be treated as case-sensitive and the values will have the same format from their corresponding LDAP entries.
|
||||
emptyClientProfilesInstructions=There are no profiles, select 'Create client profile' to create a new client profile
|
||||
policyProvider.js=Define conditions for your permissions using JavaScript. It is one of the rule-based policy types supported by Keycloak, and provides flexibility to write any policy based on the Evaluation API.
|
||||
idpType.social=Social login
|
||||
|
||||
@ -51,12 +51,7 @@ public class UserStorageProviderModel extends CacheableStorageProviderModel {
|
||||
|
||||
public boolean isImportEnabled() {
|
||||
if (importEnabled == null) {
|
||||
String val = getConfig().getFirst(IMPORT_ENABLED);
|
||||
if (val == null) {
|
||||
importEnabled = true;
|
||||
} else {
|
||||
importEnabled = Boolean.valueOf(val);
|
||||
}
|
||||
importEnabled = Boolean.parseBoolean(getConfig().getFirstOrDefault(IMPORT_ENABLED, Boolean.TRUE.toString()));
|
||||
}
|
||||
return importEnabled;
|
||||
}
|
||||
|
||||
@ -458,9 +458,30 @@ public class LDAPProvidersIntegrationTest extends AbstractLDAPTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernameAndEmailInLowerCaseFromLDAP() {
|
||||
public void testUsernameAndEmailCaseSensitiveIfImportDisabled() {
|
||||
testingClient.server().run(session -> {
|
||||
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||
UserStorageProviderModel ldapModel = ctx.getLdapProvider().getModel();
|
||||
ldapModel.setImportEnabled(false);
|
||||
ctx.getRealm().updateComponent(ldapModel);
|
||||
LDAPObject ldapObject = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), ctx.getRealm(), "JBrown8", "John", "Brown8", "JBrown8@Email.org", null, "1234");
|
||||
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), ldapObject, "Password1");
|
||||
UserModel model = session.users().searchForUserStream(ctx.getRealm(), Map.of(UserModel.USERNAME, "JBrown8")).findAny().orElse(null);
|
||||
Assert.assertNotNull(model);
|
||||
assertEquals("JBrown8", model.getUsername());
|
||||
assertEquals("JBrown8@Email.org", model.getEmail());
|
||||
ldapModel.setImportEnabled(true);
|
||||
ctx.getRealm().updateComponent(ldapModel);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUsernameAndEmailCaseInSensitiveIfImportEnabled() {
|
||||
testingClient.server().run(session -> {
|
||||
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||
UserStorageProviderModel ldapModel = ctx.getLdapProvider().getModel();
|
||||
ldapModel.setImportEnabled(true);
|
||||
ctx.getRealm().updateComponent(ldapModel);
|
||||
LDAPObject ldapObject = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), ctx.getRealm(), "JBrown9", "John", "Brown9", "JBrown9@Email.org", null, "1234");
|
||||
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), ldapObject, "Password1");
|
||||
UserModel model = session.users().searchForUserStream(ctx.getRealm(), Map.of(UserModel.USERNAME, "JBrown9")).findAny().orElse(null);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user