diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
index 3176506..4c28ad6 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java
@@ -23,6 +23,7 @@ import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
+import org.keycloak.models.cache.CachedObject;
import org.keycloak.models.cache.infinispan.entities.CachedClient;
import java.security.MessageDigest;
@@ -36,7 +37,7 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class ClientAdapter implements ClientModel {
+public class ClientAdapter implements ClientModel, CachedObject {
protected RealmCacheSession cacheSession;
protected RealmModel cachedRealm;
@@ -70,6 +71,11 @@ public class ClientAdapter implements ClientModel {
}
@Override
+ public long getCacheTimestamp() {
+ return cached.getCacheTimestamp();
+ }
+
+ @Override
public void updateClient() {
if (updated != null) updated.updateClient();
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
index 17cacc8..dd62377 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
@@ -1336,8 +1336,14 @@ public class RealmAdapter implements CachedRealmModel {
public void executeEvictions(ComponentModel model) {
if (model == null) return;
- // test that this is a realm component
- if (model.getParentId() != null && !model.getParentId().equals(getId())) return;
+ // If not realm component, check to see if it is a user storage provider child component (i.e. LDAP mapper)
+ if (model.getParentId() != null && !model.getParentId().equals(getId())) {
+ ComponentModel parent = getComponent(model.getParentId());
+ if (parent != null && UserStorageProvider.class.getName().equals(parent.getProviderType())) {
+ session.userCache().evict(this);
+ }
+ return;
+ }
// invalidate entire user cache if we're dealing with user storage SPI
if (UserStorageProvider.class.getName().equals(model.getProviderType())) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java
index c8c2f52..eb231db 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java
@@ -228,49 +228,6 @@ public class ClientStorageTest extends AbstractTestRealmKeycloakTest {
events.clear();
}
- /*
-
- @Test
- public void testDailyEviction() {
-
- // set eviction to 1 hour from now
- Calendar eviction = Calendar.getInstance();
- eviction.add(Calendar.HOUR, 1);
- ComponentRepresentation propProviderRW = testRealmResource().components().component(propProviderRWId).toRepresentation();
- propProviderRW.getConfig().putSingle(CACHE_POLICY, CacheableStorageProviderModel.CachePolicy.EVICT_DAILY.name());
- propProviderRW.getConfig().putSingle(EVICTION_HOUR, Integer.toString(eviction.get(HOUR_OF_DAY)));
- propProviderRW.getConfig().putSingle(EVICTION_MINUTE, Integer.toString(eviction.get(MINUTE)));
- testRealmResource().components().component(propProviderRWId).update(propProviderRW);
-
- // now
- testingClient.server().run(session -> {
- RealmModel realm = session.realms().getRealmByName("test");
- UserModel user = session.users().getUserByUsername("thor", realm);
- });
-
- // run twice to make sure its in cache.
- testingClient.server().run(session -> {
- RealmModel realm = session.realms().getRealmByName("test");
- UserModel user = session.users().getUserByUsername("thor", realm);
- System.out.println("User class: " + user.getClass());
- Assert.assertTrue(user instanceof CachedUserModel); // should still be cached
- });
-
- setTimeOffset(2 * 60 * 60); // 2 hours in future
-
- testingClient.server().run(session -> {
- RealmModel realm = session.realms().getRealmByName("test");
- UserModel user = session.users().getUserByUsername("thor", realm);
- System.out.println("User class: " + user.getClass());
- Assert.assertFalse(user instanceof CachedUserModel); // should be evicted
- });
-
- }
-
-
- */
-
-
@Test
public void testDailyEviction() {
testIsCached();
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
index 48228a2..d446985 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
@@ -167,16 +167,36 @@ public class UserStorageTest {
KeycloakSession session = keycloakRule.startSession();
RealmModel realm = session.realms().getRealmByName("test");
CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
- long thorTimestamp = thor.getCacheTimestamp();
+ long lastTimestamp = thor.getCacheTimestamp();
realm.updateComponent(model);
keycloakRule.stopSession(session, true);
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ lastTimestamp = thor.getCacheTimestamp();
+ realm.updateComponent(model);
+ keycloakRule.stopSession(session, true);
+
+ // test is cached
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ // thor should be evicted because we changed the model
+ Assert.assertTrue(thor.getCacheTimestamp() > lastTimestamp);
+ lastTimestamp = thor.getCacheTimestamp();
+ keycloakRule.stopSession(session, true);
+
+
Time.setOffset(60 * 2 * 60); // 2 hours
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("test");
UserModel thor2 = session.users().getUserByUsername("thor", realm);
- Assert.assertFalse(thor2 instanceof CachedUserModel);
+ // thor should be evicted because we put it 2 hours in the future
+ if (thor2 instanceof CachedUserModel) {
+ Assert.assertTrue(((CachedUserModel)thor2).getCacheTimestamp() > lastTimestamp);
+ }
model.getConfig().remove("cachePolicy");
model.getConfig().remove("evictionHour");
model.getConfig().remove("evictionMinute");
@@ -199,24 +219,46 @@ public class UserStorageTest {
KeycloakSession session = keycloakRule.startSession();
RealmModel realm = session.realms().getRealmByName("test");
- CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
realm.updateComponent(model);
keycloakRule.stopSession(session, true);
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ long lastTimestamp = thor.getCacheTimestamp();
+ keycloakRule.stopSession(session, true);
+
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ lastTimestamp = thor.getCacheTimestamp();
+ keycloakRule.stopSession(session, true);
+
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ lastTimestamp = thor.getCacheTimestamp();
+ keycloakRule.stopSession(session, true);
+
Time.setOffset(60 * 60 * 24 * 2); // 2 days in future, should be cached still
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("test");
// test still
- UserModel thor2 = session.users().getUserByUsername("thor", realm);
- Assert.assertTrue(thor2 instanceof CachedUserModel);
+ thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ Assert.assertEquals(thor.getCacheTimestamp(), lastTimestamp);
+ lastTimestamp = thor.getCacheTimestamp();
keycloakRule.stopSession(session, true);
+
Time.setOffset(Time.getOffset() + 60 * 60 * 24 * 3); // 3 days into future, cache will be invalidated
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("test");
- thor2 = session.users().getUserByUsername("thor", realm);
- Assert.assertFalse(thor2 instanceof CachedUserModel);
+ UserModel thor2 = session.users().getUserByUsername("thor", realm);
+ // thor should be evicted because we put it 2 hours in the future
+ if (thor2 instanceof CachedUserModel) {
+ Assert.assertTrue(((CachedUserModel)thor2).getCacheTimestamp() > lastTimestamp);
+ }
model.getConfig().remove("cachePolicy");
model.getConfig().remove("evictionHour");
model.getConfig().remove("evictionMinute");
@@ -233,24 +275,44 @@ public class UserStorageTest {
KeycloakSession session = keycloakRule.startSession();
RealmModel realm = session.realms().getRealmByName("test");
- CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
realm.updateComponent(model);
keycloakRule.stopSession(session, true);
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ long lastTimestamp = thor.getCacheTimestamp();
+ keycloakRule.stopSession(session, true);
+
+
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ lastTimestamp = thor.getCacheTimestamp();
+ keycloakRule.stopSession(session, true);
+
+
Time.setOffset(60 * 5); // 5 minutes in future, should be cached still
+ session = keycloakRule.startSession();
+ realm = session.realms().getRealmByName("test");
+ thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
+ Assert.assertEquals(thor.getCacheTimestamp(), lastTimestamp);
+ lastTimestamp = thor.getCacheTimestamp();
+ keycloakRule.stopSession(session, true);
+
+ Time.setOffset(60 * 20); // 20 minutes into future, cache will be invalidated
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("test");
- // test still
UserModel thor2 = session.users().getUserByUsername("thor", realm);
- Assert.assertTrue(thor2 instanceof CachedUserModel);
+ // thor should be evicted because we put it 2 hours in the future
+ if (thor2 instanceof CachedUserModel) {
+ Assert.assertTrue(((CachedUserModel)thor2).getCacheTimestamp() > lastTimestamp);
+ }
keycloakRule.stopSession(session, true);
- Time.setOffset(60 * 20); // 20 minutes into future, cache will be invalidated
session = keycloakRule.startSession();
realm = session.realms().getRealmByName("test");
- thor2 = session.users().getUserByUsername("thor", realm);
- Assert.assertFalse(thor2 instanceof CachedUserModel);
model.getConfig().remove("cachePolicy");
model.getConfig().remove("maxLifespan");
realm.updateComponent(model);