KEYCLOAK-13442 Backwards compatibility in users searching. searchForUser(String, RealmModel, int, int) is no longer called when searching users from the admin console
This commit is contained in:
parent
4b6e46d1a9
commit
6f62c0ed98
5 changed files with 91 additions and 17 deletions
|
@ -60,6 +60,7 @@ import javax.persistence.criteria.Subquery;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -814,19 +815,10 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
|
|||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
||||
TypedQuery<UserEntity> query = em.createNamedQuery("searchForUser", UserEntity.class);
|
||||
query.setParameter("realmId", realm.getId());
|
||||
query.setParameter("search", "%" + search.toLowerCase() + "%");
|
||||
if (firstResult != -1) {
|
||||
query.setFirstResult(firstResult);
|
||||
}
|
||||
if (maxResults != -1) {
|
||||
query.setMaxResults(maxResults);
|
||||
}
|
||||
List<UserEntity> results = query.getResultList();
|
||||
List<UserModel> users = new LinkedList<>();
|
||||
for (UserEntity entity : results) users.add(new UserAdapter(session, realm, em, entity));
|
||||
return users;
|
||||
Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put(UserModel.SEARCH, search);
|
||||
session.setAttribute(UserModel.INCLUDE_SERVICE_ACCOUNT, false);
|
||||
return searchForUser(attributes, realm, firstResult, maxResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,8 +44,6 @@ import java.util.Collection;
|
|||
@NamedQueries({
|
||||
@NamedQuery(name="getAllUsersByRealm", query="select u from UserEntity u where u.realmId = :realmId order by u.username"),
|
||||
@NamedQuery(name="getAllUsersByRealmExcludeServiceAccount", query="select u from UserEntity u where u.realmId = :realmId and (u.serviceAccountClientLink is null) order by u.username"),
|
||||
@NamedQuery(name="searchForUser", query="select u from UserEntity u where u.realmId = :realmId and (u.serviceAccountClientLink is null) and " +
|
||||
"( lower(u.username) like :search or lower(concat(coalesce(u.firstName, ''), ' ', coalesce(u.lastName, ''))) like :search or u.email like :search ) order by u.username"),
|
||||
@NamedQuery(name="searchForUserCount", query="select count(u) from UserEntity u where u.realmId = :realmId and (u.serviceAccountClientLink is null) and " +
|
||||
"( lower(u.username) like :search or lower(concat(coalesce(u.firstName, ''), ' ', coalesce(u.lastName, ''))) like :search or u.email like :search )"),
|
||||
@NamedQuery(name="getRealmUserByUsername", query="select u from UserEntity u where u.username = :username and u.realmId = :realmId"),
|
||||
|
|
|
@ -588,7 +588,11 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
|
||||
List<UserModel> results = query((provider, first, max) -> {
|
||||
if (provider instanceof UserQueryProvider) {
|
||||
if (attributes.containsKey(UserModel.SEARCH)) {
|
||||
return ((UserQueryProvider)provider).searchForUser(attributes.get(UserModel.SEARCH), realm, first, max);
|
||||
} else {
|
||||
return ((UserQueryProvider)provider).searchForUser(attributes, realm, first, max);
|
||||
}
|
||||
|
||||
}
|
||||
return Collections.EMPTY_LIST;
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
|
||||
package org.keycloak.testsuite.federation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.common.util.Time;
|
||||
|
@ -31,6 +34,7 @@ import org.keycloak.credential.CredentialInputUpdater;
|
|||
import org.keycloak.credential.CredentialInputValidator;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.credential.hash.PasswordHashProvider;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.OTPPolicy;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
@ -44,6 +48,7 @@ import org.keycloak.storage.StorageId;
|
|||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
|
||||
import org.keycloak.storage.user.UserLookupProvider;
|
||||
import org.keycloak.storage.user.UserQueryProvider;
|
||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
||||
|
||||
/**
|
||||
|
@ -54,7 +59,8 @@ import org.keycloak.storage.user.UserRegistrationProvider;
|
|||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class BackwardsCompatibilityUserStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater, CredentialInputValidator {
|
||||
public class BackwardsCompatibilityUserStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider,
|
||||
CredentialInputUpdater, CredentialInputValidator, UserQueryProvider {
|
||||
|
||||
private static final Logger log = Logger.getLogger(BackwardsCompatibilityUserStorage.class);
|
||||
|
||||
|
@ -304,6 +310,69 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
|||
return users.remove(user.getUsername()) != null;
|
||||
}
|
||||
|
||||
|
||||
// UserQueryProvider methods
|
||||
|
||||
@Override
|
||||
public int getUsersCount(RealmModel realm) {
|
||||
return users.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getUsers(RealmModel realm) {
|
||||
return getUsers(realm, -1, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
|
||||
return users.values()
|
||||
.stream()
|
||||
.skip(firstResult).limit(maxResults)
|
||||
.map(myUser -> createUser(realm, myUser.username))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(String search, RealmModel realm) {
|
||||
return searchForUser(search, realm, -1, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
||||
UserModel user = getUserByUsername(search, realm);
|
||||
return user == null ? Collections.emptyList() : Arrays.asList(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
|
||||
// Assume that this is not supported
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
||||
// Assume that this is not supported
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
// Assume that this is not supported
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||
// Assume that this is not supported
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
|
||||
// Assume that this is not supported
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
|
|
@ -250,6 +250,17 @@ public class BackwardsCompatibilityUserStorageTest extends AbstractAuthTest {
|
|||
loginSuccessAndLogout("otp1", "pass");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchUserStorage() {
|
||||
String userId = addUserAndResetPassword("searching", "pass");
|
||||
getCleanup().addUserId(userId);
|
||||
|
||||
// Uses same parameters as admin console when searching users
|
||||
List<UserRepresentation> users = testRealmResource().users().search("searching", 0, 20, true);
|
||||
Assert.assertNames(users, "searching");
|
||||
}
|
||||
|
||||
// return created totpSecret
|
||||
private String setupOTPForUserWithRequiredAction(String userId) {
|
||||
// Add required action to the user to reset OTP
|
||||
|
|
Loading…
Reference in a new issue