diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java index 80af0b4c95..68c5eeca24 100755 --- a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java +++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java @@ -27,6 +27,7 @@ import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; @@ -382,8 +383,13 @@ public class LDAPStorageProvider implements UserStorageProvider, searchLDAP(realm, search, firstResult, maxResults) : searchLDAPByAttributes(realm, params, firstResult, maxResults); - return StreamsUtil.paginatedStream(result.filter(filterLocalUsers(realm)), firstResult, maxResults) - .map(ldapObject -> importUserFromLDAP(session, realm, ldapObject)); + if (model.isImportEnabled()) { + result = result.filter(filterLocalUsers(realm)); + } + return StreamsUtil.paginatedStream( + result.map(ldapObject -> importUserFromLDAP(session, realm, ldapObject, false)) + .filter(Objects::nonNull), + firstResult, maxResults); } @Override @@ -619,6 +625,10 @@ public class LDAPStorageProvider implements UserStorageProvider, } protected UserModel importUserFromLDAP(KeycloakSession session, RealmModel realm, LDAPObject ldapUser) { + return importUserFromLDAP(session, realm, ldapUser, true); + } + + protected UserModel importUserFromLDAP(KeycloakSession session, RealmModel realm, LDAPObject ldapUser, boolean duplicates) { String ldapUsername = LDAPUtils.getUsername(ldapUser, ldapIdentityStore.getConfig()); LDAPUtils.checkUuid(ldapUser, ldapIdentityStore.getConfig()); @@ -633,6 +643,10 @@ public class LDAPStorageProvider implements UserStorageProvider, if (UserStorageUtil.userCache(session) != null) { UserStorageUtil.userCache(session).evict(realm, existingLocalUser); } + if (!duplicates) { + // if duplicates are not wanted return null + return null; + } } else { imported = UserStoragePrivateUtil.userLocalStorage(session).addUser(realm, ldapUsername); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java index 80715c40e4..2a7459ab1b 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPProvidersIntegrationTest.java @@ -1182,6 +1182,24 @@ public class LDAPProvidersIntegrationTest extends AbstractLDAPTest { Assert.assertNotNull(session.users().getUserByUsername(appRealm, "johnkeycloak")); }); + // change username + testingClient.server().run(session -> { + LDAPTestContext ctx = LDAPTestContext.init(session); + RealmModel appRealm = ctx.getRealm(); + UserModel user = session.users().getUserByUsername(appRealm, "johnkeycloak"); + + // change username locally + user.setUsername("johnkeycloak-renamed"); + }); + + // check user is found just once + List users = testRealm().users().search("johnkeycloak", 0, 2); + Assert.assertEquals("More than one user is found", 1, users.size()); + List components = testRealm().components().query( + testRealm().toRepresentation().getId(), UserStorageProvider.class.getName(), "test-ldap"); + Assert.assertEquals("LDAP component not found", 1, users.size()); + Assert.assertEquals(components.iterator().next().getId(), users.iterator().next().getFederationLink()); + // Revert testingClient.server().run(session -> { LDAPTestContext ctx = LDAPTestContext.init(session);