Do not automatically re-import users if they already exist locally when searching by attributes
Closes #32870 Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
22f9d2077e
commit
92e435f192
2 changed files with 64 additions and 11 deletions
|
@ -94,7 +94,6 @@ import org.keycloak.storage.user.ImportedUserValidation;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
import org.keycloak.storage.user.UserQueryMethodsProvider;
|
import org.keycloak.storage.user.UserQueryMethodsProvider;
|
||||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
import org.keycloak.storage.user.UserRegistrationProvider;
|
||||||
import org.keycloak.userprofile.AttributeContext;
|
|
||||||
import org.keycloak.userprofile.AttributeGroupMetadata;
|
import org.keycloak.userprofile.AttributeGroupMetadata;
|
||||||
import org.keycloak.userprofile.AttributeMetadata;
|
import org.keycloak.userprofile.AttributeMetadata;
|
||||||
import org.keycloak.userprofile.UserProfileDecorator;
|
import org.keycloak.userprofile.UserProfileDecorator;
|
||||||
|
@ -297,7 +296,15 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ldapObjects.stream().map(ldapUser -> importUserFromLDAP(session, realm, ldapUser));
|
return ldapObjects.stream().map(ldapUser -> {
|
||||||
|
String ldapUsername = LDAPUtils.getUsername(ldapUser, this.ldapIdentityStore.getConfig());
|
||||||
|
UserModel localUser = UserStoragePrivateUtil.userLocalStorage(session).getUserByUsername(realm, ldapUsername);
|
||||||
|
if (localUser == null) {
|
||||||
|
return importUserFromLDAP(session, realm, ldapUser);
|
||||||
|
} else {
|
||||||
|
return proxy(realm, localUser, ldapUser, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean synchronizeRegistrations() {
|
public boolean synchronizeRegistrations() {
|
||||||
|
|
|
@ -38,7 +38,11 @@ import org.junit.runners.MethodSorters;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.models.LDAPConstants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.UserProvider;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.storage.DatastoreProvider;
|
||||||
|
import org.keycloak.storage.datastore.DefaultDatastoreProvider;
|
||||||
import org.keycloak.testsuite.admin.ApiUtil;
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
import org.keycloak.testsuite.util.LDAPRule;
|
import org.keycloak.testsuite.util.LDAPRule;
|
||||||
import org.keycloak.testsuite.util.LDAPTestUtils;
|
import org.keycloak.testsuite.util.LDAPTestUtils;
|
||||||
|
@ -205,6 +209,48 @@ public class LDAPSearchForUsersPaginationTest extends AbstractLDAPTest {
|
||||||
Assert.assertTrue("Duplicated user created", adminClient.realm(TEST_REALM_NAME).users().search("john", true).isEmpty());
|
Assert.assertTrue("Duplicated user created", adminClient.realm(TEST_REALM_NAME).users().search("john", true).isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchByUserAttributeDoesNotTriggerUserReimport() {
|
||||||
|
|
||||||
|
testingClient.server().run(session -> {
|
||||||
|
// add a new user for testing that searching by attributes should not cause the user to be re-imported.
|
||||||
|
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||||
|
RealmModel appRealm = ctx.getRealm();
|
||||||
|
LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "bwayne", "Bruce", "Wayne", "bwayne@waynecorp.com", "Gotham Avenue", "666");
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server(TEST_REALM_NAME).run(session -> {
|
||||||
|
// check the user doesn't yet exist in Keycloak
|
||||||
|
UserProvider localProvider = ((DefaultDatastoreProvider) session.getProvider(DatastoreProvider.class)).userLocalStorage();
|
||||||
|
UserModel user = localProvider.getUserByUsername(session.getContext().getRealm(), "bwayne");
|
||||||
|
Assert.assertNull(user);
|
||||||
|
|
||||||
|
// import the user by searching for its username, and check it has the timestamp set by one of the LDAP mappers.
|
||||||
|
user = session.users().getUserByUsername(session.getContext().getRealm(), "bwayne");
|
||||||
|
Assert.assertNotNull(user);
|
||||||
|
Assert.assertNotNull(user.getAttributes().get("createTimestamp"));
|
||||||
|
|
||||||
|
// remove the create timestamp from the user.
|
||||||
|
user.removeAttribute("createTimestamp");
|
||||||
|
user = localProvider.getUserByUsername(session.getContext().getRealm(), "bwayne");
|
||||||
|
Assert.assertNull(user.getAttributes().get("createTimestamp"));
|
||||||
|
});
|
||||||
|
|
||||||
|
testingClient.server(TEST_REALM_NAME).run(session -> {
|
||||||
|
// search users by user attribute - the existing user SHOULD NOT be re-imported (GHI #32870)
|
||||||
|
List<UserModel> users = session.users().searchForUserByUserAttributeStream(session.getContext().getRealm(), "street", "Gotham Avenue").toList();
|
||||||
|
Assert.assertEquals(1, users.size());
|
||||||
|
UserModel user = users.get(0);
|
||||||
|
// create timestamp won't be null because it is provided directly from the LDAP mapper, so it should still be visible.
|
||||||
|
Assert.assertNotNull(user.getAttributes().get("createTimestamp"));
|
||||||
|
|
||||||
|
// however, the local stored attribute should not have been updated (i.e. user should not have been fully re-imported).
|
||||||
|
UserProvider localProvider = ((DefaultDatastoreProvider) session.getProvider(DatastoreProvider.class)).userLocalStorage();
|
||||||
|
user = localProvider.getUserByUsername(session.getContext().getRealm(), "bwayne");
|
||||||
|
Assert.assertNull(user.getAttributes().get("createTimestamp"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setLDAPEnabled(final boolean enabled) {
|
private void setLDAPEnabled(final boolean enabled) {
|
||||||
testingClient.server().run((KeycloakSession session) -> {
|
testingClient.server().run((KeycloakSession session) -> {
|
||||||
LDAPTestContext ctx = LDAPTestContext.init(session);
|
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||||
|
|
Loading…
Reference in a new issue