Problem/Motivation
We run this module next to another system that writes its own attributes on
the same Keycloak accounts. Those attributes kept vanishing, and it took us a
while to work out where they went.
updateUser() sends Keycloak a user representation whose
attributes array is built from the configured field mappings only
— see getSafeUserData(), which starts from an empty array.
Keycloak takes that array as the complete set, so everything missing from it is
dropped from the account.
The first time Drupal saves a user, every attribute this module does not know
about is therefore gone. No warning, nothing in the log. Whatever was reading
those values sees an empty field from then on.
Steps to reproduce
- Set the module up with at least one field mapping.
- Pick a user and give their Keycloak account an extra attribute in the
admin console, sayexample_attribute. - Save that user in Drupal.
- Look at the account again. Only the mapped attributes are left.
We are on Keycloak 26, declarative user profile, unmanaged attribute policy
ENABLED.
Proposed resolution
Read what the account currently carries and merge it underneath the mapped
values, so the mapping still wins and nothing else is touched. The user lookup
updateUser() already does returns the attributes, so in practice
this costs no extra request; if they are missing from that response, fetch the
user once.
If the current attributes cannot be read at all, better to skip the update
and log it than to send a request that wipes them.
Patch against 1.0.11 attached, that is what we are running.
Remaining tasks
- Review.
insertUser()may need the same treatment when the account
already exists. We have not run into that case.- Tests.
Issue fork keycloak_user_sync-3624171
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
roromedia commentedThanks Daniel! Merged together with #3624189. On top of your commits I added the adaptation to the new lookup helper from #3624189 (your code read $search_response[0], which no longer exists after that change), left the attribute map out of the request when it is empty, and added unit tests.
Verified against Keycloak 26 with unmanaged attributes enabled: example_attribute survives a save with "update existing fields" both off and on.
Your open task about insertUser(): no change needed, createUser() returns early when the account already exists and never writes to it.
Comment #8
daniel.pernold commentedThanks Roland for cleaning up and merging!
Comment #9
daniel.pernold commentedLooking forward for a new release. :-)