From 4253a79eb2a1cc1440eb37613f307e5d5a1556dc Mon Sep 17 00:00:00 2001 From: Pedro Ruivo Date: Tue, 17 Feb 2026 15:57:38 +0000 Subject: [PATCH] Client or role parsing caching should be realm specific Closes #46403 Signed-off-by: Pedro Ruivo <1492066+pruivo@users.noreply.github.com> Co-authored-by: Pedro Ruivo <1492066+pruivo@users.noreply.github.com> --- .../cache/DefaultAlternativeLookupProvider.java | 17 +++++++++++------ .../model/AlternativeLookupProviderTest.java | 5 +++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/services/src/main/java/org/keycloak/cache/DefaultAlternativeLookupProvider.java b/services/src/main/java/org/keycloak/cache/DefaultAlternativeLookupProvider.java index 6ead0bd2929..4dca551a2fb 100644 --- a/services/src/main/java/org/keycloak/cache/DefaultAlternativeLookupProvider.java +++ b/services/src/main/java/org/keycloak/cache/DefaultAlternativeLookupProvider.java @@ -109,7 +109,7 @@ public class DefaultAlternativeLookupProvider implements AlternativeLookupProvid String appName = roleName.substring(0, scopeIndex); ClientModel client = realm.getClientByClientId(appName); if (client != null) { - return storeClientRoleInCache(client, roleName, roleName.substring(scopeIndex + 1), counter); + return storeClientRoleInCache(client, cachedRoleKey(realm, roleName), roleName.substring(scopeIndex + 1), counter); } scopeIndex = roleName.lastIndexOf(CLIENT_ROLE_SEPARATOR, scopeIndex - 1); @@ -127,27 +127,28 @@ public class DefaultAlternativeLookupProvider implements AlternativeLookupProvid } private RoleModel findRoleInCache(RealmModel realm, String roleName) { - var cachedRole = lookupCache.get(roleName); + var cacheKey = cachedRoleKey(realm, roleName); + var cachedRole = lookupCache.get(cacheKey); if (!(cachedRole instanceof CachedValue.CachedRoleQualifier cachedRoleQualifier)) { return null; } if (cachedRoleQualifier.isRealmRole()) { var role = realm.getRole(cachedRoleQualifier.roleName()); if (role == null) { - lookupCache.invalidate(roleName); + lookupCache.invalidate(cacheKey); } return role; } var client = realm.getClientByClientId(cachedRoleQualifier.clientId()); if (client == null) { - lookupCache.invalidate(roleName); + lookupCache.invalidate(cacheKey); return null; } var role = client.getRole(cachedRoleQualifier.roleName()); if (role == null) { - lookupCache.invalidate(roleName); + lookupCache.invalidate(cacheKey); } return role; } @@ -168,8 +169,12 @@ public class DefaultAlternativeLookupProvider implements AlternativeLookupProvid var roleModel = realm.getRole(roleName); if (roleModel != null) { // only cache if the role is present - lookupCache.put(roleName, CachedValue.ofRealmRole(roleName)); + lookupCache.put(cachedRoleKey(realm, roleName), CachedValue.ofRealmRole(roleName)); } return roleModel; } + + private static String cachedRoleKey(RealmModel realm, String roleName) { + return realm.getId() + roleName; + } } diff --git a/tests/base/src/test/java/org/keycloak/tests/model/AlternativeLookupProviderTest.java b/tests/base/src/test/java/org/keycloak/tests/model/AlternativeLookupProviderTest.java index 262def8a8c0..795f4972f09 100644 --- a/tests/base/src/test/java/org/keycloak/tests/model/AlternativeLookupProviderTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/model/AlternativeLookupProviderTest.java @@ -71,6 +71,11 @@ public class AlternativeLookupProviderTest { counter.incrementAndGet(); return null; } + + @Override + public String getId() { + return "realm"; + } }; String badRoleName = ".";