Handle SCIM filter predicate case-insensitive matching correctly - #51530
Handle SCIM filter predicate case-insensitive matching correctly#51530elhichaouiYassine wants to merge 1 commit into
Conversation
04ea69b to
da3c5c7
Compare
There was a problem hiding this comment.
Pull request overview
Adds storage-aware case-insensitive SCIM filtering while preserving database index usage.
Changes:
- Marks usernames and emails as lowercase-stored.
- Normalizes filter values without wrapping lowercase-stored columns in
LOWER(). - Adds case-insensitive user search coverage.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
scim/core/.../Attribute.java |
Adds lowercase-storage metadata. |
scim/model/.../ScimJPAPredicateProvider.java |
Applies storage-aware predicate normalization. |
scim/model/.../UserCoreModelSchema.java |
Marks usernames and emails lowercase-stored. |
scim/tests/.../UserTest.java |
Tests case-insensitive email and username searches. |
| assertEquals(expected.getEmail().toLowerCase(), actual.getEmail().toLowerCase()); | ||
|
|
||
| // userName is case-insensitive per RFC 7643 | ||
| result = client.users().search("userName eq \"" + expected.getUserName().toUpperCase() + "\"").getResources(); |
There was a problem hiding this comment.
Not applicable - verified manually against Postgres with EXPLAIN ANALYZE.
da3c5c7 to
7f088c8
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
scim/model/src/main/java/org/keycloak/scim/model/filter/ScimJPAPredicateProvider.java:147
- Please add integration coverage for mixed-case
userNameandemails.valuefilters. The existingFilterTestonly uses lowercase values, so the regression this branch changes and the newstoredLowerCasepath are not verified.
if (value != null && (attrInfo.isStoredLowerCase() || !attrInfo.isCaseExact())) {
value = value.toString().toLowerCase();
if (!attrInfo.isStoredLowerCase()) {
expression = cb.lower((Expression<String>) expression);
}
sguilhen
left a comment
There was a problem hiding this comment.
LGTM - solid fix for both the index bypass and the email case-sensitivity bug.
Verified against Postgres with a test realm:
| Query pattern | Index usable? | Result |
|---|---|---|
username = ? (with fix) |
Yes - (realm_id, username) unique index |
Correct |
LOWER(username) = ? (old) |
No - bypasses index, forces seq scan | Correct but slow |
email = lower(?) (with fix) |
Yes - idx_user_email |
Correct |
email = 'UPPER@CASE' (old) |
N/A | Bug: 0 rows |
End-to-end SCIM filter calls with mixed-case input (userName eq "TESTUSER1", emails eq "UPPER@CASE", emails.value eq "UPPER@CASE") all return the expected results.
Two minor observations:
-
Naming inconsistency: the setter is
setStoredLowercase()(lowercase 'c') while the field isstoredLowerCase, the getter isisStoredLowerCase(), and the builder method isstoredLowerCase(). Should besetStoredLowerCase()to match. -
Test coverage for the email fix: bug (b) is a functional correctness change -
emails eq "UPPERCASE@EMAIL"previously returned 0 results. The existingFilterTest.testFilterByEmailonly uses lowercase email values, so the new behavior isn't covered. A test filtering with a mixed-case email value would lock this in.
Closes keycloak#51401 Signed-off-by: elhichaouiYassine <etu_elhichaoui.yassine@emsi-edu.ma>
7f088c8 to
0924d70
Compare
|
Thanks for the fix, @elhichaouiYassine . @pedroigor can you run the CI for this one? |
|
CI is now running |
Closes #51401
Logs: