KEYCLOAK-13163 Fixed searching for user with fine-grained permissions
This commit is contained in:
parent
8cfd4d60e6
commit
99aba33980
7 changed files with 48 additions and 18 deletions
|
@ -336,19 +336,7 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
||||||
@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) {
|
||||||
Map<String, String> attributes = new HashMap<String, String>();
|
Map<String, String> attributes = new HashMap<String, String>();
|
||||||
int spaceIndex = search.lastIndexOf(' ');
|
attributes.put(UserModel.SEARCH,search);
|
||||||
if (spaceIndex > -1) {
|
|
||||||
String firstName = search.substring(0, spaceIndex).trim();
|
|
||||||
String lastName = search.substring(spaceIndex).trim();
|
|
||||||
attributes.put(UserModel.FIRST_NAME, firstName);
|
|
||||||
attributes.put(UserModel.LAST_NAME, lastName);
|
|
||||||
} else if (search.indexOf('@') > -1) {
|
|
||||||
attributes.put(UserModel.USERNAME, search.trim().toLowerCase());
|
|
||||||
attributes.put(UserModel.EMAIL, search.trim().toLowerCase());
|
|
||||||
} else {
|
|
||||||
attributes.put(UserModel.LAST_NAME, search.trim());
|
|
||||||
attributes.put(UserModel.USERNAME, search.trim().toLowerCase());
|
|
||||||
}
|
|
||||||
return searchForUser(attributes, realm, firstResult, maxResults);
|
return searchForUser(attributes, realm, firstResult, maxResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,6 +347,23 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
||||||
|
String search = params.get(UserModel.SEARCH);
|
||||||
|
if(search!=null) {
|
||||||
|
int spaceIndex = search.lastIndexOf(' ');
|
||||||
|
if (spaceIndex > -1) {
|
||||||
|
String firstName = search.substring(0, spaceIndex).trim();
|
||||||
|
String lastName = search.substring(spaceIndex).trim();
|
||||||
|
params.put(UserModel.FIRST_NAME, firstName);
|
||||||
|
params.put(UserModel.LAST_NAME, lastName);
|
||||||
|
} else if (search.indexOf('@') > -1) {
|
||||||
|
params.put(UserModel.USERNAME, search.trim().toLowerCase());
|
||||||
|
params.put(UserModel.EMAIL, search.trim().toLowerCase());
|
||||||
|
} else {
|
||||||
|
params.put(UserModel.LAST_NAME, search.trim());
|
||||||
|
params.put(UserModel.USERNAME, search.trim().toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<UserModel> searchResults =new LinkedList<UserModel>();
|
List<UserModel> searchResults =new LinkedList<UserModel>();
|
||||||
|
|
||||||
List<LDAPObject> ldapUsers = searchLDAP(realm, params, maxResults + firstResult);
|
List<LDAPObject> ldapUsers = searchLDAP(realm, params, maxResults + firstResult);
|
||||||
|
|
|
@ -849,6 +849,21 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case UserModel.SEARCH:
|
||||||
|
List<Predicate> orPredicates = new ArrayList();
|
||||||
|
|
||||||
|
orPredicates.add(builder.like(builder.lower(root.get(UserModel.USERNAME)), "%" + value.toLowerCase() + "%"));
|
||||||
|
orPredicates.add(builder.like(builder.lower(root.get(UserModel.EMAIL)), "%" + value.toLowerCase() + "%"));
|
||||||
|
orPredicates.add(builder.like(
|
||||||
|
builder.lower(builder.concat(builder.concat(
|
||||||
|
builder.coalesce(root.get(UserModel.FIRST_NAME), builder.literal("")), " "),
|
||||||
|
builder.coalesce(root.get(UserModel.LAST_NAME), builder.literal("")))),
|
||||||
|
"%" + value.toLowerCase() + "%"));
|
||||||
|
|
||||||
|
predicates.add(builder.or(orPredicates.toArray(new Predicate[orPredicates.size()])));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case UserModel.USERNAME:
|
case UserModel.USERNAME:
|
||||||
case UserModel.FIRST_NAME:
|
case UserModel.FIRST_NAME:
|
||||||
case UserModel.LAST_NAME:
|
case UserModel.LAST_NAME:
|
||||||
|
|
|
@ -37,6 +37,7 @@ public interface UserModel extends RoleMapperModel {
|
||||||
String LOCALE = "locale";
|
String LOCALE = "locale";
|
||||||
String INCLUDE_SERVICE_ACCOUNT = "keycloak.session.realm.users.query.include_service_account";
|
String INCLUDE_SERVICE_ACCOUNT = "keycloak.session.realm.users.query.include_service_account";
|
||||||
String GROUPS = "keycloak.session.realm.users.query.groups";
|
String GROUPS = "keycloak.session.realm.users.query.groups";
|
||||||
|
String SEARCH = "keycloak.session.realm.users.query.search";
|
||||||
|
|
||||||
interface UserRemovedEvent extends ProviderEvent {
|
interface UserRemovedEvent extends ProviderEvent {
|
||||||
RealmModel getRealm();
|
RealmModel getRealm();
|
||||||
|
|
|
@ -214,7 +214,9 @@ public class UsersResource {
|
||||||
userModels = Arrays.asList(userModel);
|
userModels = Arrays.asList(userModel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
userModels = session.users().searchForUser(search.trim(), realm, firstResult, maxResults);
|
Map<String, String> attributes = new HashMap<>();
|
||||||
|
attributes.put(UserModel.SEARCH, search.trim());
|
||||||
|
return searchForUser(attributes, realm, userPermissionEvaluator, briefRepresentation, firstResult, maxResults, false);
|
||||||
}
|
}
|
||||||
} else if (last != null || first != null || email != null || username != null) {
|
} else if (last != null || first != null || email != null || username != null) {
|
||||||
Map<String, String> attributes = new HashMap<>();
|
Map<String, String> attributes = new HashMap<>();
|
||||||
|
|
|
@ -345,6 +345,7 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case UserModel.USERNAME:
|
case UserModel.USERNAME:
|
||||||
|
case UserModel.SEARCH:
|
||||||
userStream = userStream.filter(s -> s.toLowerCase().contains(value.toLowerCase()));
|
userStream = userStream.filter(s -> s.toLowerCase().contains(value.toLowerCase()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,9 +192,10 @@ public class UserPropertyFileStorage implements UserLookupProvider, UserStorageP
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
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) {
|
||||||
String username = attributes.get(UserModel.USERNAME);
|
String search = Optional.ofNullable(attributes.get(UserModel.USERNAME))
|
||||||
if (username == null) return Collections.EMPTY_LIST;
|
.orElseGet(()-> attributes.get(UserModel.SEARCH));
|
||||||
return searchForUser(username, realm, firstResult, maxResults);
|
if (search == null) return Collections.EMPTY_LIST;
|
||||||
|
return searchForUser(search, realm, firstResult, maxResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -894,7 +894,6 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
|
||||||
GroupModel customerAGroup = session.realms().createGroup(realm, "Customer A");
|
GroupModel customerAGroup = session.realms().createGroup(realm, "Customer A");
|
||||||
UserModel customerAManager = session.users().addUser(realm, "customer-a-manager");
|
UserModel customerAManager = session.users().addUser(realm, "customer-a-manager");
|
||||||
session.userCredentialManager().updateCredential(realm, customerAManager, UserCredentialModel.password("password"));
|
session.userCredentialManager().updateCredential(realm, customerAManager, UserCredentialModel.password("password"));
|
||||||
customerAManager.joinGroup(customerAGroup);
|
|
||||||
ClientModel realmAdminClient = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
ClientModel realmAdminClient = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
customerAManager.grantRole(realmAdminClient.getRole(AdminRoles.QUERY_USERS));
|
customerAManager.grantRole(realmAdminClient.getRole(AdminRoles.QUERY_USERS));
|
||||||
customerAManager.setEnabled(true);
|
customerAManager.setEnabled(true);
|
||||||
|
@ -969,6 +968,11 @@ public class FineGrainAdminUnitTest extends AbstractKeycloakTest {
|
||||||
Assert.assertEquals(20, result.size());
|
Assert.assertEquals(20, result.size());
|
||||||
Assert.assertThat(result, Matchers.everyItem(Matchers.hasProperty("username", Matchers.startsWith("b"))));
|
Assert.assertThat(result, Matchers.everyItem(Matchers.hasProperty("username", Matchers.startsWith("b"))));
|
||||||
|
|
||||||
|
result = client.realm("test").users().search("test", -1, 20, false);
|
||||||
|
|
||||||
|
Assert.assertEquals(20, result.size());
|
||||||
|
Assert.assertThat(result, Matchers.everyItem(Matchers.hasProperty("username", Matchers.startsWith("b"))));
|
||||||
|
|
||||||
result = client.realm("test").users().search("a", -1, 20, false);
|
result = client.realm("test").users().search("a", -1, 20, false);
|
||||||
|
|
||||||
Assert.assertEquals(0, result.size());
|
Assert.assertEquals(0, result.size());
|
||||||
|
|
Loading…
Reference in a new issue