keycloak / keycloak

Open Source Identity and Access Management For Modern Applications and Services
https://www.keycloak.org
Apache License 2.0
23.09k stars 6.72k forks source link

realm-role assigned to user not effective until Keycloak is restarted #9342

Closed beenham closed 7 months ago

beenham commented 2 years ago

Describe the bug

When granting / deleting a realm role to the user via a custom SPI using KeycloakSession, the realm role is not assigned in any auth / access tokens, or in the admin web interface until after a restart of keycloak.

The error also looks to affect attributes.

The database is getting updated as expected.

Version

16.1.0

Expected behavior

User realm-role to be assigned/updated instantly to be used in auth tokens.

Actual behavior

User realm-role does not get updated until after restart of Keycloak

How to Reproduce?

Create an SPI with the following code:

final RealmModel realm = session.getContext().getRealm();
final UserProvider userProvider = session.userStorageManager();
final UserModel user = userProvider..searchForUserByUserAttributeStream(getRealm(), "someAttribute", "someValue").findFirst().orElse(null);
final RoleModel roleModel = session.roles().getRealmRole(realm, roleNameString);
user.grantRole(roleModel);

Check users role mapping in the admin web interface

Restart Keycloak and verify role is assigned to user post-restart

Anything else?

I came across a stack overflow question which seems to be having a similar issue: https://stackoverflow.com/questions/70358302/springboot-keycloak-admin-cli-realm-role-udpate-effective-only-after-application

beenham commented 2 years ago

I have found a workaround.. Once retrieved a UserModel from the search using your custom attribute, performing a lookup with the retrieved UserModel ID.

session.users().getUserById(realm, user.getId())

Editing / adding roles to the retrieved UserModel from this persists and is effective immediately. It is not ideal, but it does the job for now.

ahus1 commented 2 years ago

I analyzed this and found the probable cause for this. Describing the workaround you found helped me to analyze this issue. Thank you very much for providing it.

You're probably running an Infinispan Cache in your setup, and that would then route all calls to session.users() through UserCacheSession.

My analysis for the cause: When calling UserCacheSession#getUserById(), this will wrap all returned user instances with org.keycloak.models.cache.infinispan.UserAdapter, that would then trigger a cache invalidation. For the data returned by searchForUserByUserAttributeStream, the users will not be wrapped, therefore all changes will not invalidate the cache.

I agree this is an API with a sharp edge. The upcoming implementation Keycloak.X storage will most likely change that.

Until then, let's consider some options:

keycloak-github-bot[bot] commented 7 months ago

Thanks for reporting this issue. However, after review this is not considered a valid issue, or has been recently resolved.

As the issue is not valid it will be automatically closed.