Problem/Motivation
We had users whose Keycloak account never picked up anything from Drupal.
No error, the sync reported success, the account just stayed as it was. What
they had in common: their login name occurs inside somebody else's login name.
KeycloakService looks an account up by username in three places
— insertUser(), updateUser() and
deleteUser() — and all three call
GET /admin/realms/{realm}/users with username and no
exact. Keycloak treats that as a substring search, and the code
then takes $search_response[0], whichever account happens to sort
first.
In order of how much it hurts:
deleteUser()can delete a different person's account.insertUser()can decide the user already exists and never
create it.updateUser()writes this user's data onto the other account.
With unique mail addresses enforced in the realm that fails on the
conflict, so the update is simply lost — which is the quiet version
we ran into.
Steps to reproduce
- Two Drupal users, say
anaandanastasia, both
synced to Keycloak. - Change a mapped field on
anaand save. - Watch the request. The PUT goes to anastasia's account id. Either it is
refused because the mail address belongs to ana, or ana's data lands on
anastasia.
Short or common names make this easy to hit — anything like
mail that appears inside other names.
Proposed resolution
Pass exact=true on the three lookups. Usernames are unique in a
realm, so the exact search returns the account that was asked for.
Remaining tasks
- Review.
- Possibly check the returned username as well, in case an older Keycloak
ignores the parameter. - Tests.
Issue fork keycloak_user_sync-3624189
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #5
roromedia commentedComment #7
daniel.pernold commentedThanks Roland for cleaning up and merging!