From b17b5550b35f7c7ce0e368f4d296cdecb3abd69c Mon Sep 17 00:00:00 2001 From: Stefan Guilhen Date: Tue, 14 Jul 2026 12:17:44 -0300 Subject: [PATCH] Add lower-bound validation on SCIM count parameter Closes #50471 Signed-off-by: Stefan Guilhen --- .../group/GroupResourceTypeProvider.java | 2 +- .../model/user/UserResourceTypeProvider.java | 2 +- .../tests/scim/tck/PaginationTest.java | 22 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/scim/model/src/main/java/org/keycloak/scim/model/group/GroupResourceTypeProvider.java b/scim/model/src/main/java/org/keycloak/scim/model/group/GroupResourceTypeProvider.java index 2d2fcd5521f4..3b0560d4204a 100644 --- a/scim/model/src/main/java/org/keycloak/scim/model/group/GroupResourceTypeProvider.java +++ b/scim/model/src/main/java/org/keycloak/scim/model/group/GroupResourceTypeProvider.java @@ -122,7 +122,7 @@ protected Stream getModels(SearchRequest searchRequest) { RealmModel realm = session.getContext().getRealm(); Integer firstResult = searchRequest.getStartIndex() != null ? searchRequest.getStartIndex() - 1 : null; Integer maxResults = searchRequest.getCount(); - maxResults = maxResults != null ? Math.min(maxResults, DEFAULT_MAX_RESULTS) : DEFAULT_MAX_RESULTS; + maxResults = maxResults != null ? Math.max(0, Math.min(maxResults, DEFAULT_MAX_RESULTS)) : DEFAULT_MAX_RESULTS; if (StringUtil.isNotBlank(searchRequest.getFilter())) { // parse filter into AST diff --git a/scim/model/src/main/java/org/keycloak/scim/model/user/UserResourceTypeProvider.java b/scim/model/src/main/java/org/keycloak/scim/model/user/UserResourceTypeProvider.java index f28d7a7a624f..4ec7612bc84a 100644 --- a/scim/model/src/main/java/org/keycloak/scim/model/user/UserResourceTypeProvider.java +++ b/scim/model/src/main/java/org/keycloak/scim/model/user/UserResourceTypeProvider.java @@ -137,7 +137,7 @@ protected Stream getModels(SearchRequest searchRequest) { RealmModel realm = session.getContext().getRealm(); Integer firstResult = searchRequest.getStartIndex() != null ? searchRequest.getStartIndex() - 1 : null; Integer maxResults = searchRequest.getCount(); - maxResults = maxResults != null ? Math.min(maxResults, DEFAULT_MAX_RESULTS) : DEFAULT_MAX_RESULTS; + maxResults = maxResults != null ? Math.max(0, Math.min(maxResults, DEFAULT_MAX_RESULTS)) : DEFAULT_MAX_RESULTS; if (StringUtil.isNotBlank(searchRequest.getFilter())) { // parse filter into AST diff --git a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/PaginationTest.java b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/PaginationTest.java index 2fb940bbe119..e86b97fce11d 100644 --- a/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/PaginationTest.java +++ b/scim/tests/base/src/test/java/org/keycloak/tests/scim/tck/PaginationTest.java @@ -240,6 +240,28 @@ public void testGroupSearchRespectsMaxResults() { assertThat(response.getStartIndex(), is(1)); } + @Test + public void testUserSearchWithNegativeCount() { + createUser("user-0", "User 0", "Test", "user0@keycloak.org", true); + + ListResponse response = client.users().search(null, 1, -5); + assertThat(response, is(not(nullValue()))); + assertThat(response.getTotalResults(), is(1)); + assertThat(response.getItemsPerPage(), is(0)); + assertThat(response.getResources().size(), is(0)); + } + + @Test + public void testGroupSearchWithNegativeCount() { + createGroup("group-0"); + + ListResponse response = client.groups().search(null, 1, -5); + assertThat(response, is(not(nullValue()))); + assertThat(response.getTotalResults(), is(1)); + assertThat(response.getItemsPerPage(), is(0)); + assertThat(response.getResources().size(), is(0)); + } + private User createUser(String username, String givenName, String familyName, String email, boolean active) { User user = new User(); user.setUserName(username);