mirror of
https://github.com/keycloak/keycloak.git
synced 2026-06-08 16:42:13 -04:00
Respect storage provider cache policies for federated roles and groups
RealmCacheSession unconditionally cached federated roles and groups without checking the storage provider's configured cache policy. This meant policies like NO_CACHE, MAX_LIFESPAN, EVICT_DAILY, and EVICT_WEEKLY were silently ignored for roles and groups, even though they worked correctly for clients. Apply the same cache policy pattern used by cacheClient() and validateCache() to roles and groups: - On cache miss: check isEnabled() and getCachePolicy() before storing, skip caching for NO_CACHE, and apply lifespan for timed policies - On cache hit: validate with shouldInvalidate() and reload from delegate if the cached entry has expired per the configured policy Closes #47660 Signed-off-by: Asish Kumar <officialasishkumar@gmail.com>
This commit is contained in:
parent
6250f9d57c
commit
88bb22bb20
1 changed files with 136 additions and 24 deletions
|
|
@ -78,10 +78,13 @@ import org.keycloak.models.cache.infinispan.events.RoleAddedEvent;
|
|||
import org.keycloak.models.cache.infinispan.events.RoleRemovedEvent;
|
||||
import org.keycloak.models.cache.infinispan.events.RoleUpdatedEvent;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.storage.CacheableStorageProviderModel;
|
||||
import org.keycloak.storage.DatastoreProvider;
|
||||
import org.keycloak.storage.StorageId;
|
||||
import org.keycloak.storage.StoreManagers;
|
||||
import org.keycloak.storage.client.ClientStorageProviderModel;
|
||||
import org.keycloak.storage.group.GroupStorageProviderModel;
|
||||
import org.keycloak.storage.role.RoleStorageProviderModel;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
|
@ -932,15 +935,79 @@ public class RealmCacheSession implements CacheRealmProvider {
|
|||
return managedRoles.get(id);
|
||||
}
|
||||
|
||||
CachedRole cached = getCachedRole(realm, id);
|
||||
if (cached == null) {
|
||||
return null;
|
||||
CachedRole cached = cache.get(id, CachedRole.class);
|
||||
if (cached != null && !cached.getRealm().equals(realm.getId())) {
|
||||
cached = null;
|
||||
}
|
||||
|
||||
RoleModel adapter;
|
||||
if (cached != null) {
|
||||
adapter = validateCachedRole(realm, cached);
|
||||
} else {
|
||||
adapter = cacheRole(realm, id);
|
||||
}
|
||||
if (adapter instanceof RoleAdapter roleAdapter) {
|
||||
managedRoles.put(id, roleAdapter);
|
||||
}
|
||||
RoleAdapter adapter = new RoleAdapter(cached,this, realm);
|
||||
managedRoles.put(id, adapter);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
private RoleModel cacheRole(RealmModel realm, String id) {
|
||||
long loaded = cache.getCurrentRevision(id);
|
||||
RoleModel model = getRoleDelegate().getRoleById(realm, id);
|
||||
if (model == null) return null;
|
||||
|
||||
StorageId storageId = new StorageId(id);
|
||||
if (!storageId.isLocal()) {
|
||||
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||
RoleStorageProviderModel providerModel = new RoleStorageProviderModel(component);
|
||||
if (!providerModel.isEnabled()) {
|
||||
return model;
|
||||
}
|
||||
CacheableStorageProviderModel.CachePolicy policy = providerModel.getCachePolicy();
|
||||
if (policy == CacheableStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||
return model;
|
||||
}
|
||||
|
||||
CachedRole cached = createCachedRole(loaded, model, realm);
|
||||
long lifespan = providerModel.getLifespan();
|
||||
if (lifespan > 0) {
|
||||
cache.addRevisioned(cached, startupRevision, lifespan);
|
||||
} else {
|
||||
cache.addRevisioned(cached, startupRevision);
|
||||
}
|
||||
return new RoleAdapter(cached, this, realm);
|
||||
}
|
||||
|
||||
CachedRole cached = createCachedRole(loaded, model, realm);
|
||||
cache.addRevisioned(cached, startupRevision);
|
||||
return new RoleAdapter(cached, this, realm);
|
||||
}
|
||||
|
||||
private RoleModel validateCachedRole(RealmModel realm, CachedRole cached) {
|
||||
StorageId storageId = new StorageId(cached.getId());
|
||||
if (!storageId.isLocal()) {
|
||||
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
RoleStorageProviderModel model = new RoleStorageProviderModel(component);
|
||||
if (model.shouldInvalidate(cached)) {
|
||||
String containerId = (cached instanceof CachedClientRole) ? ((CachedClientRole) cached).getClientId() : realm.getId();
|
||||
registerRoleInvalidation(cached.getId(), cached.getName(), containerId);
|
||||
return getRoleDelegate().getRoleById(realm, cached.getId());
|
||||
}
|
||||
}
|
||||
return new RoleAdapter(cached, this, realm);
|
||||
}
|
||||
|
||||
private CachedRole createCachedRole(long loaded, RoleModel model, RealmModel realm) {
|
||||
if (model.isClientRole()) {
|
||||
return new CachedClientRole(loaded, model.getContainerId(), model, realm);
|
||||
}
|
||||
return new CachedRealmRole(loaded, model, realm);
|
||||
}
|
||||
|
||||
protected CachedRole getCachedRole(RealmModel realm, String id) {
|
||||
CachedRole cached = cache.get(id, CachedRole.class);
|
||||
if (cached != null && !cached.getRealm().equals(realm.getId())) {
|
||||
|
|
@ -951,11 +1018,7 @@ public class RealmCacheSession implements CacheRealmProvider {
|
|||
long loaded = cache.getCurrentRevision(id);
|
||||
RoleModel model = getRoleDelegate().getRoleById(realm, id);
|
||||
if (model == null) return null;
|
||||
if (model.isClientRole()) {
|
||||
cached = new CachedClientRole(loaded, model.getContainerId(), model, realm);
|
||||
} else {
|
||||
cached = new CachedRealmRole(loaded, model, realm);
|
||||
}
|
||||
cached = createCachedRole(loaded, model, realm);
|
||||
cache.addRevisioned(cached, startupRevision);
|
||||
}
|
||||
return cached;
|
||||
|
|
@ -963,29 +1026,78 @@ public class RealmCacheSession implements CacheRealmProvider {
|
|||
|
||||
@Override
|
||||
public GroupModel getGroupById(RealmModel realm, String id) {
|
||||
if (invalidations.contains(id)) {
|
||||
return getGroupDelegate().getGroupById(realm, id);
|
||||
} else if (managedGroups.containsKey(id)) {
|
||||
return managedGroups.get(id);
|
||||
}
|
||||
|
||||
CachedGroup cached = cache.get(id, CachedGroup.class);
|
||||
if (cached != null && !cached.getRealm().equals(realm.getId())) {
|
||||
cached = null;
|
||||
}
|
||||
|
||||
if (cached == null) {
|
||||
long loaded = cache.getCurrentRevision(id);
|
||||
GroupModel model = getGroupDelegate().getGroupById(realm, id);
|
||||
if (model == null) return null;
|
||||
if (invalidations.contains(id)) return model;
|
||||
cached = new CachedGroup(loaded, realm, model);
|
||||
cache.addRevisioned(cached, startupRevision);
|
||||
|
||||
} else if (invalidations.contains(id)) {
|
||||
return getGroupDelegate().getGroupById(realm, id);
|
||||
} else if (managedGroups.containsKey(id)) {
|
||||
return managedGroups.get(id);
|
||||
GroupModel adapter;
|
||||
if (cached != null) {
|
||||
adapter = validateCachedGroup(realm, cached);
|
||||
} else {
|
||||
adapter = cacheGroup(realm, id);
|
||||
}
|
||||
if (adapter instanceof GroupAdapter groupAdapter) {
|
||||
managedGroups.put(id, groupAdapter);
|
||||
}
|
||||
GroupAdapter adapter = new GroupAdapter(cached, this, session, realm);
|
||||
managedGroups.put(id, adapter);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
private GroupModel cacheGroup(RealmModel realm, String id) {
|
||||
long loaded = cache.getCurrentRevision(id);
|
||||
GroupModel model = getGroupDelegate().getGroupById(realm, id);
|
||||
if (model == null) return null;
|
||||
if (invalidations.contains(id)) return model;
|
||||
|
||||
StorageId storageId = new StorageId(id);
|
||||
if (!storageId.isLocal()) {
|
||||
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||
GroupStorageProviderModel providerModel = new GroupStorageProviderModel(component);
|
||||
if (!providerModel.isEnabled()) {
|
||||
return model;
|
||||
}
|
||||
CacheableStorageProviderModel.CachePolicy policy = providerModel.getCachePolicy();
|
||||
if (policy == CacheableStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||
return model;
|
||||
}
|
||||
|
||||
CachedGroup cachedGroup = new CachedGroup(loaded, realm, model);
|
||||
long lifespan = providerModel.getLifespan();
|
||||
if (lifespan > 0) {
|
||||
cache.addRevisioned(cachedGroup, startupRevision, lifespan);
|
||||
} else {
|
||||
cache.addRevisioned(cachedGroup, startupRevision);
|
||||
}
|
||||
return new GroupAdapter(cachedGroup, this, session, realm);
|
||||
}
|
||||
|
||||
CachedGroup cachedGroup = new CachedGroup(loaded, realm, model);
|
||||
cache.addRevisioned(cachedGroup, startupRevision);
|
||||
return new GroupAdapter(cachedGroup, this, session, realm);
|
||||
}
|
||||
|
||||
private GroupModel validateCachedGroup(RealmModel realm, CachedGroup cached) {
|
||||
StorageId storageId = new StorageId(cached.getId());
|
||||
if (!storageId.isLocal()) {
|
||||
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||
if (component == null) {
|
||||
return null;
|
||||
}
|
||||
GroupStorageProviderModel model = new GroupStorageProviderModel(component);
|
||||
if (model.shouldInvalidate(cached)) {
|
||||
registerGroupInvalidation(cached.getId());
|
||||
return getGroupDelegate().getGroupById(realm, cached.getId());
|
||||
}
|
||||
}
|
||||
return new GroupAdapter(cached, this, session, realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel getGroupByName(RealmModel realm, GroupModel parent, String name) {
|
||||
String cacheKey = getGroupByNameCacheKey(realm.getId(), parent != null? parent.getId(): null, name);
|
||||
|
|
|
|||
Loading…
Reference in a new issue