mirror of
https://github.com/keycloak/keycloak.git
synced 2026-02-03 20:39:33 -05:00
User REST Admin API - count and search returns different amount of users
Closes #45219 Signed-off-by: Martin Kanis <mkanis@redhat.com>
This commit is contained in:
parent
fcc9ade022
commit
4f91b5246e
3 changed files with 99 additions and 1 deletions
|
|
@ -401,6 +401,38 @@ public interface UsersResource {
|
|||
@QueryParam("idpUserId") String idpUserId,
|
||||
@QueryParam("q") String searchQuery);
|
||||
|
||||
/**
|
||||
* Returns the number of users that can be viewed and match the given filters.
|
||||
* Includes support for exact matching.
|
||||
*
|
||||
* @param search arbitrary search string for all the fields below
|
||||
* @param last last name field of a user
|
||||
* @param first first name field of a user
|
||||
* @param email email field of a user
|
||||
* @param emailVerified emailVerified field of a user
|
||||
* @param username username field of a user
|
||||
* @param enabled Boolean representing if user is enabled or not
|
||||
* @param idpAlias The alias of an Identity Provider linked to the user
|
||||
* @param idpUserId The userId at an Identity Provider linked to the user
|
||||
* @param exact Boolean which defines whether the params must match exactly
|
||||
* @param searchQuery A query to search for custom attributes
|
||||
* @return number of users matching the given filters
|
||||
*/
|
||||
@Path("count")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Integer count(@QueryParam("search") String search,
|
||||
@QueryParam("lastName") String last,
|
||||
@QueryParam("firstName") String first,
|
||||
@QueryParam("email") String email,
|
||||
@QueryParam("emailVerified") Boolean emailVerified,
|
||||
@QueryParam("username") String username,
|
||||
@QueryParam("enabled") Boolean enabled,
|
||||
@QueryParam("idpAlias") String idpAlias,
|
||||
@QueryParam("idpUserId") String idpUserId,
|
||||
@QueryParam("exact") Boolean exact,
|
||||
@QueryParam("q") String searchQuery);
|
||||
|
||||
/**
|
||||
* Returns the number of users with the given status for emailVerified.
|
||||
* If none of the filters is specified this is equivalent to {{@link #count()}}.
|
||||
|
|
|
|||
|
|
@ -450,7 +450,8 @@ public class UsersResource {
|
|||
return session.users().getUsersCount(realm, parameters);
|
||||
}
|
||||
}
|
||||
} else if (last != null || first != null || email != null || username != null || emailVerified != null || enabled != null || !searchAttributes.isEmpty()) {
|
||||
} else if (last != null || first != null || email != null || username != null || emailVerified != null
|
||||
|| idpAlias != null || idpUserId != null || enabled != null || exact != null || !searchAttributes.isEmpty()) {
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
if (last != null) {
|
||||
parameters.put(UserModel.LAST_NAME, last);
|
||||
|
|
|
|||
|
|
@ -788,4 +788,69 @@ public class UserSearchTest extends AbstractUserTest {
|
|||
users = managedRealm.admin().users().search("username", 0, 20);
|
||||
assertEquals(9, users.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountAndSearchConsistencyWithMissingParameters() {
|
||||
createUser("user1", "user1@example.com");
|
||||
|
||||
// Count users before creating service account (should be 1 regular user)
|
||||
Integer countBefore = managedRealm.admin().users().count(null, null, null, null, null, null, null, null, null, true, null);
|
||||
assertEquals(1, countBefore.intValue(), "Should have 1 regular user before service account creation");
|
||||
|
||||
ClientRepresentation client = new ClientRepresentation();
|
||||
client.setClientId("service-account-client");
|
||||
client.setServiceAccountsEnabled(true);
|
||||
client.setEnabled(true);
|
||||
client.setPublicClient(false);
|
||||
client.setSecret("secret");
|
||||
client.setRedirectUris(Arrays.asList("http://localhost"));
|
||||
|
||||
String clientId = ApiUtil.getCreatedId(managedRealm.admin().clients().create(client));
|
||||
|
||||
// Count users after creating service account (should be 2: 1 regular + 1 service account)
|
||||
Integer countAfter = managedRealm.admin().users().count(null, null, null, null, null, null, null, null, null, true, null);
|
||||
assertEquals(2, countAfter.intValue(), "Should have 2 users after service account creation (1 regular + 1 service account)");
|
||||
|
||||
// exact=true inconsistency with service accounts
|
||||
Integer count = managedRealm.admin().users().count(null, null, null, null, null, null, null, null, null, true, null);
|
||||
List<UserRepresentation> users = managedRealm.admin().users().search(null, null, null, null, 0, 10, null, null, true);
|
||||
assertEquals(count.intValue(), users.size(), "Count and search should return same number with exact=true");
|
||||
|
||||
// idpAlias parameter with service account inclusion inconsistency
|
||||
Integer countWithIdp = managedRealm.admin().users().count(null, null, null, null, null, null, null, "nonexistent-idp", null, null);
|
||||
List<UserRepresentation> usersWithIdp = managedRealm.admin().users().search(null, null, null, null, null, "nonexistent-idp", null, 0, 10, null, null);
|
||||
assertEquals(countWithIdp.intValue(), usersWithIdp.size(), "Count and search should return same number with idpAlias parameter");
|
||||
|
||||
// idpUserId parameter with same inconsistency
|
||||
Integer countWithIdpUserId = managedRealm.admin().users().count(null, null, null, null, null, null, null, null, "nonexistent-user-id", null);
|
||||
List<UserRepresentation> usersWithIdpUserId = managedRealm.admin().users().search(null, null, null, null, null, null, "nonexistent-user-id", 0, 10, null, null);
|
||||
assertEquals(countWithIdpUserId.intValue(), usersWithIdpUserId.size(), "Count and search should return same number with idpUserId parameter");
|
||||
|
||||
managedRealm.admin().clients().get(clientId).remove();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCountAndSearchConsistencyWithIdpParameters() {
|
||||
createUser("user1", "user1@example.com");
|
||||
createUser("user2", "user2@example.com");
|
||||
|
||||
addSampleIdentityProvider("test-idp", 0);
|
||||
|
||||
// Link only user1 to the IDP
|
||||
String user1Id = managedRealm.admin().users().search("user1").get(0).getId();
|
||||
FederatedIdentityRepresentation link = new FederatedIdentityRepresentation();
|
||||
link.setUserId("external-user-id");
|
||||
link.setUserName("user1");
|
||||
addFederatedIdentity(user1Id, "test-idp", link);
|
||||
|
||||
// search with idpAlias should return 1 user, count should also return 1
|
||||
Integer countWithIdpAlias = managedRealm.admin().users().count(null, null, null, null, null, null, null, "test-idp", null, null);
|
||||
List<UserRepresentation> usersWithIdpAlias = managedRealm.admin().users().search(null, null, null, null, null, "test-idp", null, 0, 10, null, null);
|
||||
assertEquals(countWithIdpAlias.intValue(), usersWithIdpAlias.size(), "Count and search should return same number with idpAlias parameter");
|
||||
|
||||
// search with idpUserId should return 1 user, count should also return 1
|
||||
Integer countWithIdpUserId = managedRealm.admin().users().count(null, null, null, null, null, null, null, null, "external-user-id", null);
|
||||
List<UserRepresentation> usersWithIdpUserId = managedRealm.admin().users().search(null, null, null, null, null, null, "external-user-id", 0, 10, null, null);
|
||||
assertEquals(countWithIdpUserId.intValue(), usersWithIdpUserId.size(), "Count and search should return same number with idpUserId parameter");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue