diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java index 0d9ef3becf1..b4fafae823a 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java @@ -956,10 +956,14 @@ public class RealmCacheSession implements CacheRealmProvider { long loaded = cache.getCurrentRevision(id); RoleModel model = getRoleDelegate().getRoleById(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()); + if (component == null) { + return model; + } RoleStorageProviderModel providerModel = new RoleStorageProviderModel(component); if (!providerModel.isEnabled()) { return model; @@ -1015,13 +1019,18 @@ public class RealmCacheSession implements CacheRealmProvider { } if (cached == null) { - long loaded = cache.getCurrentRevision(id); - RoleModel model = getRoleDelegate().getRoleById(realm, id); - if (model == null) return null; - cached = createCachedRole(loaded, model, realm); - cache.addRevisioned(cached, startupRevision); + RoleModel model = cacheRole(realm, id); + if (model instanceof RoleAdapter roleAdapter) { + return roleAdapter.cached; + } + return null; } - return cached; + + RoleModel adapter = validateCachedRole(realm, cached); + if (adapter instanceof RoleAdapter roleAdapter) { + return roleAdapter.cached; + } + return null; } @Override @@ -1058,6 +1067,9 @@ public class RealmCacheSession implements CacheRealmProvider { StorageId storageId = new StorageId(id); if (!storageId.isLocal()) { ComponentModel component = realm.getComponent(storageId.getProviderId()); + if (component == null) { + return model; + } GroupStorageProviderModel providerModel = new GroupStorageProviderModel(component); if (!providerModel.isEnabled()) { return model; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/GroupStorageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/GroupStorageTest.java index 1e73c9a55f4..7e62085d077 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/GroupStorageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/GroupStorageTest.java @@ -27,10 +27,13 @@ import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.component.ComponentModel; import org.keycloak.models.GroupModel; import org.keycloak.models.RealmModel; +import org.keycloak.models.cache.infinispan.GroupAdapter; import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.storage.CacheableStorageProviderModel; import org.keycloak.storage.StorageId; import org.keycloak.storage.group.GroupStorageProvider; +import org.keycloak.storage.group.GroupStorageProviderModel; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.auth.page.AuthRealm; @@ -43,7 +46,9 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class GroupStorageTest extends AbstractTestRealmKeycloakTest { @@ -124,135 +129,56 @@ public class GroupStorageTest extends AbstractTestRealmKeycloakTest { }); } - /* - TODO review caching of groups, it behaves a little bit different than clients so following tests fails. - Tracked as KEYCLOAK-15135. - */ -// @Test -// public void testDailyEviction() { -// testNotCached(); + @Test + public void testNoCache() { + testIsCached(); -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// Calendar eviction = Calendar.getInstance(); -// eviction.add(Calendar.HOUR, 1); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.EVICT_DAILY); -// model.setEvictionHour(eviction.get(HOUR_OF_DAY)); -// model.setEvictionMinute(eviction.get(MINUTE)); -// realm.updateComponent(model); -// }); -// testIsCached(); -// setTimeOffset(2 * 60 * 60); // 2 hours in future -// testNotCached(); -// testIsCached(); -// -// setDefaultCachePolicy(); -// testIsCached(); + try { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + GroupStorageProviderModel model = new GroupStorageProviderModel(realm.getComponent(providerId)); + model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); + realm.updateComponent(model); + }); -// } + testNotCached(); + testNotCached(); + } finally { + setDefaultCachePolicy(); + } -// @Test -// public void testWeeklyEviction() { -// testNotCached(); -// -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// Calendar eviction = Calendar.getInstance(); -// eviction.add(Calendar.HOUR, 4 * 24); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.EVICT_WEEKLY); -// model.setEvictionDay(eviction.get(DAY_OF_WEEK)); -// model.setEvictionHour(eviction.get(HOUR_OF_DAY)); -// model.setEvictionMinute(eviction.get(MINUTE)); -// realm.updateComponent(model); -// }); -// testIsCached(); -// setTimeOffset(2 * 24 * 60 * 60); // 2 days in future -// testIsCached(); -// setTimeOffset(5 * 24 * 60 * 60); // 5 days in future -// testNotCached(); -// testIsCached(); -// -// setDefaultCachePolicy(); -// testIsCached(); -// -// } -// -// @Test -// public void testMaxLifespan() { -// testNotCached(); -// -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.MAX_LIFESPAN); -// model.setMaxLifespan(1 * 60 * 60 * 1000); -// realm.updateComponent(model); -// }); -// testIsCached(); -// -// setTimeOffset(1/2 * 60 * 60); // 1/2 hour in future -// -// testIsCached(); -// -// setTimeOffset(2 * 60 * 60); // 2 hours in future -// -// testNotCached(); -// testIsCached(); -// -// setDefaultCachePolicy(); -// testIsCached(); -// -// } + testIsCached(); + } -// private void testNotCached() { -// String providerId = this.providerId; -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// StorageId storageId = new StorageId(providerId, "hardcoded-group"); -// GroupModel hardcoded = session.groups().getGroupById(realm, storageId.getId()); -// Assert.assertNotNull(hardcoded); -// Assert.assertThat(hardcoded, not(instanceOf(GroupAdapter.class))); -// }); -// } + private void testNotCached() { + String providerId = this.providerId; + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + StorageId storageId = new StorageId(providerId, "hardcoded-group"); + GroupModel hardcoded = session.groups().getGroupById(realm, storageId.getId()); + assertNotNull(hardcoded); + assertFalse(hardcoded instanceof GroupAdapter); + }); + } -// private void testIsCached() { -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleModel hardcoded = realm.getRole("hardcoded-role"); -// Assert.assertNotNull(hardcoded); -// Assert.assertThat(hardcoded, instanceOf(RoleAdapter.class)); -// }); -// } + private void testIsCached() { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + GroupModel hardcoded = session.groups().getGroupById(realm, new StorageId(providerId, "hardcoded-group").getId()); + assertNotNull(hardcoded); + assertTrue(hardcoded instanceof GroupAdapter); + }); + } -// @Test -// public void testNoCache() { -// testNotCached(); -// -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); -// realm.updateComponent(model); -// }); -// -// testNotCached(); -// -// // test twice because updating component should evict -// testNotCached(); -// -// // set it back -// setDefaultCachePolicy(); -// testIsCached(); -// } + private void setDefaultCachePolicy() { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + GroupStorageProviderModel model = new GroupStorageProviderModel(realm.getComponent(providerId)); + model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.DEFAULT); + realm.updateComponent(model); + }); + } -// private void setDefaultCachePolicy() { -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.DEFAULT); -// realm.updateComponent(model); -// }); -// } + // TODO review caching of groups, it behaves a little bit different than clients so daily/weekly eviction tests still need attention. + // Tracked as KEYCLOAK-15135. } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/RoleStorageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/RoleStorageTest.java index f0516437270..48d65e288d6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/RoleStorageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/RoleStorageTest.java @@ -27,10 +27,13 @@ import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.component.ComponentModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; +import org.keycloak.models.cache.infinispan.RoleAdapter; import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.storage.CacheableStorageProviderModel; import org.keycloak.storage.StorageId; import org.keycloak.storage.role.RoleStorageProvider; +import org.keycloak.storage.role.RoleStorageProviderModel; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.auth.page.AuthRealm; @@ -43,7 +46,9 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class RoleStorageTest extends AbstractTestRealmKeycloakTest { @@ -133,133 +138,83 @@ public class RoleStorageTest extends AbstractTestRealmKeycloakTest { }); } - /* - TODO review caching of roles, it behaves a little bit different than clients so following tests fails. - Tracked as KEYCLOAK-14938. - */ -// @Test -// public void testDailyEviction() { -// testNotCached(); -// -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// Calendar eviction = Calendar.getInstance(); -// eviction.add(Calendar.HOUR, 1); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.EVICT_DAILY); -// model.setEvictionHour(eviction.get(HOUR_OF_DAY)); -// model.setEvictionMinute(eviction.get(MINUTE)); -// realm.updateComponent(model); -// }); -// testIsCached(); -// setTimeOffset(2 * 60 * 60); // 2 hours in future -// testNotCached(); -// testIsCached(); -// -// setDefaultCachePolicy(); -// testIsCached(); -// -// } -// -// @Test -// public void testWeeklyEviction() { -// testNotCached(); -// -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// Calendar eviction = Calendar.getInstance(); -// eviction.add(Calendar.HOUR, 4 * 24); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.EVICT_WEEKLY); -// model.setEvictionDay(eviction.get(DAY_OF_WEEK)); -// model.setEvictionHour(eviction.get(HOUR_OF_DAY)); -// model.setEvictionMinute(eviction.get(MINUTE)); -// realm.updateComponent(model); -// }); -// testIsCached(); -// setTimeOffset(2 * 24 * 60 * 60); // 2 days in future -// testIsCached(); -// setTimeOffset(5 * 24 * 60 * 60); // 5 days in future -// testNotCached(); -// testIsCached(); -// -// setDefaultCachePolicy(); -// testIsCached(); -// -// } -// -// @Test -// public void testMaxLifespan() { -// testNotCached(); -// -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.MAX_LIFESPAN); -// model.setMaxLifespan(1 * 60 * 60 * 1000); -// realm.updateComponent(model); -// }); -// testIsCached(); -// -// setTimeOffset(1/2 * 60 * 60); // 1/2 hour in future -// -// testIsCached(); -// -// setTimeOffset(2 * 60 * 60); // 2 hours in future -// -// testNotCached(); -// testIsCached(); -// -// setDefaultCachePolicy(); -// testIsCached(); -// -// } -// -// private void testNotCached() { -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleModel hardcoded = realm.getRole("hardcoded-role"); -// Assert.assertNotNull(hardcoded); -// Assert.assertThat(hardcoded, not(instanceOf(RoleAdapter.class))); -// }); -// } -// -// private void testIsCached() { -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleModel hardcoded = realm.getRole("hardcoded-role"); -// Assert.assertNotNull(hardcoded); -// Assert.assertThat(hardcoded, instanceOf(RoleAdapter.class)); -// }); -// } -// -// @Test -// public void testNoCache() { -// testNotCached(); -// -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); -// realm.updateComponent(model); -// }); -// -// testNotCached(); -// -// // test twice because updating component should evict -// testNotCached(); -// -// // set it back -// setDefaultCachePolicy(); -// testIsCached(); -// } -// -// private void setDefaultCachePolicy() { -// testingClient.server().run(session -> { -// RealmModel realm = session.realms().getRealmByName("test"); -// RoleStorageProviderModel model = realm.getRoleStorageProviders().get(0); -// model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.DEFAULT); -// realm.updateComponent(model); -// }); -// } + @Test + public void testNoCache() { + testIsCached(); + + try { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + RoleStorageProviderModel model = new RoleStorageProviderModel(realm.getComponent(providerId)); + model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.NO_CACHE); + realm.updateComponent(model); + }); + + testNotCached(); + testNotCached(); + } finally { + setDefaultCachePolicy(); + } + + testIsCached(); + } + + @Test + public void testMaxLifespan() { + testIsCached(); + + try { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + RoleStorageProviderModel model = new RoleStorageProviderModel(realm.getComponent(providerId)); + model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.MAX_LIFESPAN); + model.setMaxLifespan(1 * 60 * 60 * 1000); + realm.updateComponent(model); + }); + + testIsCached(); + + setTimeOffset(30 * 60); // 1/2 hour in future + testIsCached(); + + setTimeOffset(2 * 60 * 60); // 2 hours in future + testNotCached(); + testIsCached(); + } finally { + resetTimeOffset(); + setDefaultCachePolicy(); + } + + testIsCached(); + } + + private void testNotCached() { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + RoleModel hardcoded = realm.getRole("hardcoded-role"); + assertNotNull(hardcoded); + assertFalse(hardcoded instanceof RoleAdapter); + }); + } + + private void testIsCached() { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + RoleModel hardcoded = realm.getRole("hardcoded-role"); + assertNotNull(hardcoded); + assertTrue(hardcoded instanceof RoleAdapter); + }); + } + + private void setDefaultCachePolicy() { + testingClient.server().run(session -> { + RealmModel realm = session.realms().getRealmByName("test"); + RoleStorageProviderModel model = new RoleStorageProviderModel(realm.getComponent(providerId)); + model.setCachePolicy(CacheableStorageProviderModel.CachePolicy.DEFAULT); + realm.updateComponent(model); + }); + } + + // TODO review caching of roles, it behaves a little bit different than clients so daily/weekly eviction tests still need attention. + // Tracked as KEYCLOAK-14938. }