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.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -814,19 +815,10 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
||||||
TypedQuery<UserEntity> query = em.createNamedQuery("searchForUser", UserEntity.class);
|
Map<String, String> attributes = new HashMap<>();
|
||||||
query.setParameter("realmId", realm.getId());
|
attributes.put(UserModel.SEARCH, search);
|
||||||
query.setParameter("search", "%" + search.toLowerCase() + "%");
|
session.setAttribute(UserModel.INCLUDE_SERVICE_ACCOUNT, false);
|
||||||
if (firstResult != -1) {
|
return searchForUser(attributes, realm, firstResult, maxResults);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -44,8 +44,6 @@ import java.util.Collection;
|
||||||
@NamedQueries({
|
@NamedQueries({
|
||||||
@NamedQuery(name="getAllUsersByRealm", query="select u from UserEntity u where u.realmId = :realmId order by u.username"),
|
@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="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 " +
|
@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 )"),
|
"( 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"),
|
@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) {
|
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
|
||||||
List<UserModel> results = query((provider, first, max) -> {
|
List<UserModel> results = query((provider, first, max) -> {
|
||||||
if (provider instanceof UserQueryProvider) {
|
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 ((UserQueryProvider)provider).searchForUser(attributes, realm, first, max);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return Collections.EMPTY_LIST;
|
return Collections.EMPTY_LIST;
|
||||||
|
|
|
@ -18,10 +18,13 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.federation;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
@ -31,6 +34,7 @@ import org.keycloak.credential.CredentialInputUpdater;
|
||||||
import org.keycloak.credential.CredentialInputValidator;
|
import org.keycloak.credential.CredentialInputValidator;
|
||||||
import org.keycloak.credential.CredentialModel;
|
import org.keycloak.credential.CredentialModel;
|
||||||
import org.keycloak.credential.hash.PasswordHashProvider;
|
import org.keycloak.credential.hash.PasswordHashProvider;
|
||||||
|
import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OTPPolicy;
|
import org.keycloak.models.OTPPolicy;
|
||||||
import org.keycloak.models.PasswordPolicy;
|
import org.keycloak.models.PasswordPolicy;
|
||||||
|
@ -44,6 +48,7 @@ import org.keycloak.storage.StorageId;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
|
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
|
import org.keycloak.storage.user.UserQueryProvider;
|
||||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
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>
|
* @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);
|
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;
|
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
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,6 +250,17 @@ public class BackwardsCompatibilityUserStorageTest extends AbstractAuthTest {
|
||||||
loginSuccessAndLogout("otp1", "pass");
|
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
|
// return created totpSecret
|
||||||
private String setupOTPForUserWithRequiredAction(String userId) {
|
private String setupOTPForUserWithRequiredAction(String userId) {
|
||||||
// Add required action to the user to reset OTP
|
// Add required action to the user to reset OTP
|
||||||
|
|
Loading…
Reference in a new issue