From 1c331854477e460c1418bae8cc1f2ee4fa4fcd82 Mon Sep 17 00:00:00 2001 From: Ponshankar Date: Mon, 29 Jun 2026 12:13:12 +0530 Subject: [PATCH 1/4] Fix ArrayIndexOutOfBoundsException in SearchQueryUtils.getFields() on trailing backslash - Issue #50228 Signed-off-by: Ponshankar --- .../src/main/java/org/keycloak/utils/SearchQueryUtils.java | 4 +++- .../test/java/org/keycloak/utils/SearchQueryUtilsTest.java | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java b/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java index 2395c4664f6d..76230bb72f61 100644 --- a/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java +++ b/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java @@ -87,6 +87,7 @@ public static Map getFields(final String query) { String name = ""; while (i < chars.length && chars[i] != ':') { if (chars[i] == '\\') { + if (i + 1 >= chars.length) break; if (chars[i+1] == '\"') { i++; } @@ -114,7 +115,7 @@ else if(chars[i] == ' ' && !inQuotes) { name += chars[i]; i++; } - if(i == chars.length || chars[i] == ' ') { + if(i == chars.length || chars[i] == ' ' || chars[i] == '\\') { continue; } i++; @@ -123,6 +124,7 @@ else if(chars[i] == ' ' && !inQuotes) { String value = ""; while (i < chars.length) { if (chars[i] == '\\') { + if (i + 1 >= chars.length) break; if (chars[i+1] == '\"') { i++; } diff --git a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java index 3f7c27c0bbfa..23ae51f2dbb1 100644 --- a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java +++ b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java @@ -61,6 +61,10 @@ public void testGetFields() { testParseQuery("k:val1", "k", "val1"); + + testParseQuery("key:val\\", + "key", "val"); + } private void testParseQuery(String query, String... expectedStr) { From beac954e2b5b9eee83f49fc1abd768179001679f Mon Sep 17 00:00:00 2001 From: Ponshankar Date: Mon, 29 Jun 2026 13:05:12 +0530 Subject: [PATCH 2/4] Added more test coverage - Issue #50228 Signed-off-by: Ponshankar --- .../test/java/org/keycloak/utils/SearchQueryUtilsTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java index 23ae51f2dbb1..f6d0f6bef002 100644 --- a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java +++ b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java @@ -65,6 +65,11 @@ public void testGetFields() { testParseQuery("key:val\\", "key", "val"); + testParseQuery("key\\"); + + testParseQuery("key:\"val\\", + "key", "val"); + } private void testParseQuery(String query, String... expectedStr) { From 794b4c8f83d6c55de0b430956eb6f4ca37a8e86f Mon Sep 17 00:00:00 2001 From: Ponshankar Date: Thu, 2 Jul 2026 08:41:39 +0530 Subject: [PATCH 3/4] Reject unterminated escape sequences in search queries - Issue #50228 Signed-off-by: Ponshankar --- .../java/org/keycloak/utils/SearchQueryUtils.java | 11 ++++++++--- .../org/keycloak/utils/SearchQueryUtilsTest.java | 15 ++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java b/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java index 76230bb72f61..ded98b827106 100644 --- a/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java +++ b/services/src/main/java/org/keycloak/utils/SearchQueryUtils.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.regex.Pattern; +import org.keycloak.models.ModelValidationException; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserProvider; @@ -87,7 +88,9 @@ public static Map getFields(final String query) { String name = ""; while (i < chars.length && chars[i] != ':') { if (chars[i] == '\\') { - if (i + 1 >= chars.length) break; + if (i + 1 >= chars.length) { + throw new ModelValidationException("Invalid search query: unterminated escape sequence"); + } if (chars[i+1] == '\"') { i++; } @@ -115,7 +118,7 @@ else if(chars[i] == ' ' && !inQuotes) { name += chars[i]; i++; } - if(i == chars.length || chars[i] == ' ' || chars[i] == '\\') { + if(i == chars.length || chars[i] == ' ') { continue; } i++; @@ -124,7 +127,9 @@ else if(chars[i] == ' ' && !inQuotes) { String value = ""; while (i < chars.length) { if (chars[i] == '\\') { - if (i + 1 >= chars.length) break; + if (i + 1 >= chars.length) { + throw new ModelValidationException("Invalid search query: unterminated escape sequence"); + } if (chars[i+1] == '\"') { i++; } diff --git a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java index f6d0f6bef002..801a3fdce287 100644 --- a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java +++ b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java @@ -21,8 +21,10 @@ import java.util.Map; import org.junit.Test; +import org.keycloak.models.ModelValidationException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; /** * @author Vaclav Muzikar @@ -62,14 +64,13 @@ public void testGetFields() { testParseQuery("k:val1", "k", "val1"); - testParseQuery("key:val\\", - "key", "val"); - - testParseQuery("key\\"); - - testParseQuery("key:\"val\\", - "key", "val"); + assertInvalidQuery("key:val\\"); + assertInvalidQuery("key\\"); + assertInvalidQuery("key:\"val\\"); + } + private void assertInvalidQuery(String query) { + assertThrows(ModelValidationException.class, () -> SearchQueryUtils.getFields(query)); } private void testParseQuery(String query, String... expectedStr) { From 7e399735d131a63333a53608de56833706e0143f Mon Sep 17 00:00:00 2001 From: Ponshankar Date: Thu, 2 Jul 2026 08:53:18 +0530 Subject: [PATCH 4/4] Applied spotless for import ordering - Issue #50228 Signed-off-by: Ponshankar --- .../src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java index 801a3fdce287..2ae100cefb37 100644 --- a/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java +++ b/services/src/test/java/org/keycloak/utils/SearchQueryUtilsTest.java @@ -20,9 +20,10 @@ import java.util.HashMap; import java.util.Map; -import org.junit.Test; import org.keycloak.models.ModelValidationException; +import org.junit.Test; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows;