KEYCLOAK-13817 Return local user from LDAPStorageProvider

This commit is contained in:
Sven-Torben Janus 2020-04-21 20:36:48 +02:00 committed by Marek Posolda
parent fed34929ae
commit fcb0e450a0
4 changed files with 49 additions and 22 deletions

View file

@ -237,7 +237,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
if (localUser == null) {
UserModel imported = importUserFromLDAP(session, realm, ldapUser);
searchResults.add(imported);
} else if (shouldUserAttributeBeAlwaysReadFromLdap(realm, attrName)) {
} else {
searchResults.add(proxy(realm, localUser, ldapUser));
}
}
@ -246,20 +246,6 @@ public class LDAPStorageProvider implements UserStorageProvider,
}
}
private boolean shouldUserAttributeBeAlwaysReadFromLdap(RealmModel realm, String userAttributeName) {
List<ComponentModel> mapperModels = realm.getComponents(model.getId(), LDAPStorageMapper.class.getName());
return mapperModels.stream().anyMatch(mapperModel -> shouldUserAttributeBeAlwaysReadFromLdap(mapperModel, userAttributeName));
}
private boolean shouldUserAttributeBeAlwaysReadFromLdap(ComponentModel mapperModel, String userAttributeName) {
LDAPStorageMapper mapper = mapperManager.getMapper(mapperModel);
if (UserAttributeLDAPStorageMapper.class.isAssignableFrom(mapper.getClass())) {
UserAttributeLDAPStorageMapper userAttributeMapper = (UserAttributeLDAPStorageMapper) mapper;
return userAttributeName.equals(userAttributeMapper.getUserModelAttribute()) && userAttributeMapper.isAlwaysReadValueFromLdap();
}
return false;
}
public boolean synchronizeRegistrations() {
return "true".equalsIgnoreCase(model.getConfig().getFirst(LDAPConstants.SYNC_REGISTRATIONS)) && editMode == UserStorageProvider.EditMode.WRITABLE;
}

View file

@ -415,7 +415,7 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
}
}
public String getUserModelAttribute() {
private String getUserModelAttribute() {
return mapperModel.getConfig().getFirst(USER_MODEL_ATTRIBUTE);
}
@ -431,10 +431,6 @@ public class UserAttributeLDAPStorageMapper extends AbstractLDAPStorageMapper {
return parseBooleanParameter(mapperModel, READ_ONLY);
}
public boolean isAlwaysReadValueFromLdap() {
return parseBooleanParameter(mapperModel, ALWAYS_READ_VALUE_FROM_LDAP);
}
protected void setPropertyOnUserModel(Property<Object> userModelProperty, UserModel user, String ldapAttrValue) {
if (ldapAttrValue == null) {
userModelProperty.setValue(user, null);

View file

@ -50,13 +50,16 @@ import org.keycloak.storage.user.UserLookupProvider;
import org.keycloak.storage.user.UserQueryProvider;
import org.keycloak.storage.user.UserRegistrationProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import static org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction;
@ -624,9 +627,16 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
}
return Collections.EMPTY_LIST;
}, realm,0, Integer.MAX_VALUE - 1);
results = removeDuplicates(results);
return importValidation(realm, results);
}
private static List<UserModel> removeDuplicates(List<UserModel> withDuplicates) {
Set<UserModel> withoutDuplicates = new TreeSet<>(Comparator.comparing(UserModel::getId));
withoutDuplicates.addAll(withDuplicates);
return new ArrayList<>(withoutDuplicates);
}
@Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
if (user == null) throw new IllegalStateException("Federated user no longer valid");

View file

@ -24,7 +24,6 @@ import java.util.List;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.hamcrest.Matchers;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.ClassRule;
import org.junit.FixMethodOrder;
@ -35,6 +34,8 @@ import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.ldap.LDAPStorageProvider;
@ -52,7 +53,12 @@ import org.keycloak.testsuite.util.LDAPRule;
import org.keycloak.testsuite.util.LDAPTestUtils;
import org.keycloak.testsuite.util.MailUtils;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat;
/**
* Test for the scenarios with disabled cache for LDAP provider. This involves scenarios when something is changed directly in LDAP server
@ -147,7 +153,6 @@ public class LDAPNoCacheTest extends AbstractLDAPTest {
}
}
@Test
public void resetPasswordLinkCheckOldAddressLast() throws IOException, MessagingException {
// Trigger reset password from the login page
@ -211,4 +216,34 @@ public class LDAPNoCacheTest extends AbstractLDAPTest {
});
}
// KEYCLOAK-13817
@Test
public void lookupByAttributeAfterImportWithAttributeValueAlwaysReadFromLdapMustSucceed() {
testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel realm = ctx.getRealm();
ctx.getLdapModel().setImportEnabled(true);
realm.updateComponent(ctx.getLdapModel());
UserProvider localStorage = session.userLocalStorage();
LDAPStorageProvider ldapProvider = ctx.getLdapProvider();
// assume no user imported
UserModel user = localStorage.getUserByUsername("johnkeycloak", realm);
assumeThat(user, is(nullValue()));
// trigger import
List<UserModel> byEmail = ldapProvider.searchForUserByUserAttribute("email", "john_old@email.org", realm);
assumeThat(byEmail, hasSize(1));
// assume that user has been imported
user = localStorage.getUserByUsername("johnkeycloak", realm);
assumeThat(user, is(not(nullValue())));
// search a second time
byEmail = ldapProvider.searchForUserByUserAttribute("email", "john_old@email.org", realm);
assertThat(byEmail, hasSize(1));
});
}
}