Skip to content

Validate SCIM user inputs against Keycloak user profile rules#116

Merged
nicolamacoir merged 6 commits into
Metatavu:developfrom
msegurar02:Feat/validate-user-input-against-user-profile
Jun 15, 2026
Merged

Validate SCIM user inputs against Keycloak user profile rules#116
nicolamacoir merged 6 commits into
Metatavu:developfrom
msegurar02:Feat/validate-user-input-against-user-profile

Conversation

@msegurar02

Copy link
Copy Markdown
Contributor

Summary

Adds Keycloak user profile validation to SCIM user create, update, and patch flows.

SCIM user input is now validated against the realm's configured Keycloak user profile before users are created or modified, so profile rules such as required attributes, username/email constraints, and field validators are enforced consistently through the SCIM API.

Changes

  • Validate SCIM user create, update, and patch requests using Keycloak's UserProfileProvider.
  • Convert Keycloak user profile validation failures into SCIM-compliant error responses.
  • Support organization emailAsUsername mappings while still providing Keycloak's internal username value for profile validation.
  • Add shared handling for validation errors in realm and organization SCIM user endpoints.
  • Update tests to assert structured SCIM Error responses.
  • Ensure integration tests rebuild provider jars before running Keycloak Testcontainers.

Why

Previously, SCIM user operations could bypass validation configured in the Keycloak user profile. This meant invalid or incomplete user data could be accepted through SCIM even when the same input would be rejected by Keycloak's own user-management APIs.

This change makes SCIM user operations respect the configured Keycloak user profile and return proper SCIM error responses when validation fails.

Validation

  • Focused integration tests for affected create/update/patch flows passed.
  • Full test suite passed with ./gradlew test.

Mercedes.Segura added 2 commits June 2, 2026 15:50
…dates

- Validate SCIM user create, update, and patch requests using Keycloak's `UserProfileProvider`.
- Convert Keycloak user profile validation failures into SCIM-compliant error responses.
- Support organization `emailAsUsername` mappings while still providing Keycloak's internal `username` value for profile validation.
- Add shared handling for validation errors in realm and organization SCIM user endpoints.
- Update tests to assert structured SCIM Error responses.
- Ensure integration tests rebuild provider jars before running Keycloak Testcontainers.
@cpesch

cpesch commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

I've been stumbling about this issue, too. When will it become part of a release?

@nicolamacoir nicolamacoir left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Would be good to include this into our upcoming 1.6.0 release.

I have a few points:

  • PATCH desyncs username vs email when emailAsUsername=true. validateForPatch reseeds the map from the existing user, but on PATCH replace userName the SCIM userName→email mapping overwrites email only — username keeps the stale value. Validation runs against (new email, old username). Create/update reseed correctly; PATCH doesn't.
    ref: UserProfileValidationService.java:69-78 + UsersController.java:374-392

  • UnsupportedUserPath escapes as a 500 instead of a SCIM 400. The new pre-validation pass throws UnsupportedUserPath (unchecked); the patchUser try/catch in both ScimServer subclasses only handles UnsupportedPatchOperation and UserProfileValidationException.
    ref: UsersController.java:300-392, RealmScimServer.java:139-147, OrganizationScimServer.java:146-154

  • Test fixtures relaxed: editUsernameAllowed flipped falsetrue on both shared realms to make the new "incorrect username on update" tests pass. Every existing test now runs in a non-default Keycloak config. Use a dedicated test realm instead.
    ref: src/test/resources/kc-test.json:34, kc-organizations.json:36

  • userName/email collide on the same map key when emailAsUsername=true — the email block silently wins, so validation runs against emails[0].value even when the client sent a different userName. The duplicated "email: error-invalid-email; email: error-invalid-email" in the new test asserts this collision as expected behavior.
    ref: UserProfileValidationService.java:120-141

  • validateForPatch re-validates the entire existing user, not just patched attributes. If profile rules tightened after a user was created, an unrelated PATCH on displayName starts failing with errors on firstName/lastName/etc.

  • PATCH remove writes null into the validation map → REMOVE on a required field is indistinguishable from clearing it; returns a generic error instead of scimType=mutability. No test coverage.

  • Error responses omit scimType (RFC 7644 §3.12). PR description claims "SCIM-compliant errors"; Okta/Entra branch on this field.

  • Validation error detail leaks raw Keycloak attribute names including IDP-mapper attributes (with unmanagedAttributePolicy=ENABLED). Map back to SCIM paths before serializing.

  • Six identical try/catch blocks across RealmScimServer/OrganizationScimServer/two controllers for create/update/patch — a template method on AbstractScimServer would collapse this.

  Centralize write-path error handling and enrich SCIM error responses
  following review comments:

  - Route create/update/patch through AbstractScimServer.executeUserOperation,
    replacing duplicated per-operation try/catch in RealmScimServer and
    OrganizationScimServer; add UserOperation functional interface
  - Emit RFC 7644 scimType on error bodies via new ScimErrors helpers
    (invalidValue, invalidFilter, invalidPath, invalidSyntax, mutability,
    uniqueness) so clients get a machine-readable error category
  - Add UserAttributes.findBySourceId to resolve a Keycloak source ID to
    its SCIM attribute
  - Add validation test realms (kc-validation-test, kc-validation-orgs) with
    Realm/OrganizationUserValidationTestsIT suites and shared test bases;
    move create/update validation assertions into them
  - Fix testPatchUserAdminEvents to patch active instead of userName, which
    validation now correctly rejects when editUsernameAllowed=false
@sonarqubecloud

Copy link
Copy Markdown

@msegurar02

Copy link
Copy Markdown
Contributor Author

Changes addressed @nicolamacoir

@msegurar02
msegurar02 requested a review from nicolamacoir June 15, 2026 11:25
@nicolamacoir

Copy link
Copy Markdown
Contributor

Great work @msegurar02. LGTM!

@nicolamacoir
nicolamacoir merged commit 845b2f7 into Metatavu:develop Jun 15, 2026
3 checks passed
@msegurar02
msegurar02 deleted the Feat/validate-user-input-against-user-profile branch June 26, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants