user spi cache policy
This commit is contained in:
parent
fd86f3bda8
commit
3e28ac1e46
13 changed files with 633 additions and 38 deletions
|
@ -13,6 +13,7 @@ import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,6 +127,10 @@ public abstract class CacheManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRevisioned(Revisioned object, long startupRevision) {
|
public void addRevisioned(Revisioned object, long startupRevision) {
|
||||||
|
addRevisioned(object, startupRevision, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRevisioned(Revisioned object, long startupRevision, long lifespan) {
|
||||||
//startRevisionBatch();
|
//startRevisionBatch();
|
||||||
String id = object.getId();
|
String id = object.getId();
|
||||||
try {
|
try {
|
||||||
|
@ -164,7 +169,8 @@ public abstract class CacheManager {
|
||||||
// revisions cache has a lower value than the object.revision, so update revision and add it to cache
|
// revisions cache has a lower value than the object.revision, so update revision and add it to cache
|
||||||
if (id.endsWith("realm.clients")) RealmCacheManager.logger.tracev("adding Object.revision {0} rev {1}", object.getRevision(), rev);
|
if (id.endsWith("realm.clients")) RealmCacheManager.logger.tracev("adding Object.revision {0} rev {1}", object.getRevision(), rev);
|
||||||
revisions.put(id, object.getRevision());
|
revisions.put(id, object.getRevision());
|
||||||
cache.putForExternalRead(id, object);
|
if (lifespan < 0) cache.putForExternalRead(id, object);
|
||||||
|
else cache.putForExternalRead(id, object, lifespan, TimeUnit.MILLISECONDS);
|
||||||
} finally {
|
} finally {
|
||||||
endRevisionBatch();
|
endRevisionBatch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ package org.keycloak.models.cache.infinispan;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.cluster.ClusterProvider;
|
import org.keycloak.cluster.ClusterProvider;
|
||||||
import org.keycloak.common.constants.ServiceAccountConstants;
|
import org.keycloak.common.constants.ServiceAccountConstants;
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.CredentialValidationOutput;
|
|
||||||
import org.keycloak.models.FederatedIdentityModel;
|
import org.keycloak.models.FederatedIdentityModel;
|
||||||
import org.keycloak.models.GroupModel;
|
import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -31,7 +31,6 @@ import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserConsentModel;
|
import org.keycloak.models.UserConsentModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserProvider;
|
import org.keycloak.models.UserProvider;
|
||||||
|
@ -43,8 +42,13 @@ import org.keycloak.models.cache.infinispan.entities.CachedUser;
|
||||||
import org.keycloak.models.cache.infinispan.entities.CachedUserConsent;
|
import org.keycloak.models.cache.infinispan.entities.CachedUserConsent;
|
||||||
import org.keycloak.models.cache.infinispan.entities.CachedUserConsents;
|
import org.keycloak.models.cache.infinispan.entities.CachedUserConsents;
|
||||||
import org.keycloak.models.cache.infinispan.entities.UserListQuery;
|
import org.keycloak.models.cache.infinispan.entities.UserListQuery;
|
||||||
|
import org.keycloak.storage.StorageId;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -177,22 +181,19 @@ public class UserCacheSession implements UserCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedUser cached = cache.get(id, CachedUser.class);
|
CachedUser cached = cache.get(id, CachedUser.class);
|
||||||
UserModel delegate = null;
|
UserModel adapter = null;
|
||||||
boolean wasCached = cached != null;
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
logger.trace("not cached");
|
logger.trace("not cached");
|
||||||
Long loaded = cache.getCurrentRevision(id);
|
Long loaded = cache.getCurrentRevision(id);
|
||||||
delegate = getDelegate().getUserById(id, realm);
|
UserModel delegate = getDelegate().getUserById(id, realm);
|
||||||
if (delegate == null) {
|
if (delegate == null) {
|
||||||
logger.trace("delegate returning null");
|
logger.trace("delegate returning null");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
cached = new CachedUser(loaded, realm, delegate);
|
adapter = cacheUser(realm, delegate, loaded);
|
||||||
cache.addRevisioned(cached, startupRevision);
|
} else {
|
||||||
|
adapter = validateCache(realm, cached);
|
||||||
}
|
}
|
||||||
logger.trace("returning new cache adapter");
|
|
||||||
UserAdapter adapter = new UserAdapter(cached, this, session, realm);
|
|
||||||
if (!wasCached) onCache(realm, adapter, delegate);
|
|
||||||
managedUsers.put(id, adapter);
|
managedUsers.put(id, adapter);
|
||||||
return adapter;
|
return adapter;
|
||||||
}
|
}
|
||||||
|
@ -238,15 +239,17 @@ public class UserCacheSession implements UserCache {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
userId = model.getId();
|
userId = model.getId();
|
||||||
query = new UserListQuery(loaded, cacheKey, realm, model.getId());
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
if (invalidations.contains(userId)) return model;
|
if (invalidations.contains(userId)) return model;
|
||||||
if (managedUsers.containsKey(userId)) {
|
if (managedUsers.containsKey(userId)) {
|
||||||
logger.tracev("return managed user");
|
logger.tracev("return managed user");
|
||||||
return managedUsers.get(userId);
|
return managedUsers.get(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
UserAdapter adapter = getUserAdapter(realm, userId, loaded, model);
|
UserModel adapter = getUserAdapter(realm, userId, loaded, model);
|
||||||
|
if (adapter instanceof UserAdapter) { // this was cached, so we can cache query too
|
||||||
|
query = new UserListQuery(loaded, cacheKey, realm, model.getId());
|
||||||
|
cache.addRevisioned(query, startupRevision);
|
||||||
|
}
|
||||||
managedUsers.put(userId, adapter);
|
managedUsers.put(userId, adapter);
|
||||||
return adapter;
|
return adapter;
|
||||||
} else {
|
} else {
|
||||||
|
@ -261,21 +264,132 @@ public class UserCacheSession implements UserCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UserAdapter getUserAdapter(RealmModel realm, String userId, Long loaded, UserModel delegate) {
|
protected UserModel getUserAdapter(RealmModel realm, String userId, Long loaded, UserModel delegate) {
|
||||||
CachedUser cached = cache.get(userId, CachedUser.class);
|
CachedUser cached = cache.get(userId, CachedUser.class);
|
||||||
boolean wasCached = cached != null;
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
cached = new CachedUser(loaded, realm, delegate);
|
return cacheUser(realm, delegate, loaded);
|
||||||
|
} else {
|
||||||
|
return validateCache(realm, cached);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UserModel validateCache(RealmModel realm, CachedUser cached) {
|
||||||
|
StorageId storageId = new StorageId(cached.getId());
|
||||||
|
if (!storageId.isLocal()) {
|
||||||
|
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel(component);
|
||||||
|
UserStorageProviderModel.CachePolicy policy = model.getCachePolicy();
|
||||||
|
// although we do set a timeout, Infinispan has no guarantees when the user will be evicted
|
||||||
|
// its also hard to test stuff
|
||||||
|
boolean invalidate = false;
|
||||||
|
if (policy != null) {
|
||||||
|
String currentTime = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(Time.currentTimeMillis()));
|
||||||
|
if (policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||||
|
invalidate = true;
|
||||||
|
} else if (cached.getCacheTimestamp() < model.getCacheInvalidBefore()) {
|
||||||
|
invalidate = true;
|
||||||
|
} else if (policy == UserStorageProviderModel.CachePolicy.EVICT_DAILY) {
|
||||||
|
long dailyTimeout = dailyTimeout(model.getEvictionHour(), model.getEvictionMinute());
|
||||||
|
dailyTimeout = dailyTimeout - (24 * 60 * 60 * 1000);
|
||||||
|
//String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(dailyTimeout));
|
||||||
|
//String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
||||||
|
if (cached.getCacheTimestamp() <= dailyTimeout) {
|
||||||
|
invalidate = true;
|
||||||
|
}
|
||||||
|
} else if (policy == UserStorageProviderModel.CachePolicy.EVICT_WEEKLY) {
|
||||||
|
int oneWeek = 7 * 24 * 60 * 60 * 1000;
|
||||||
|
long weeklyTimeout = weeklyTimeout(model.getEvictionDay(), model.getEvictionHour(), model.getEvictionMinute());
|
||||||
|
long lastTimeout = weeklyTimeout - oneWeek;
|
||||||
|
String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(weeklyTimeout));
|
||||||
|
String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
||||||
|
if (cached.getCacheTimestamp() <= lastTimeout) {
|
||||||
|
invalidate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalidate) {
|
||||||
|
registerUserInvalidation(realm, cached);
|
||||||
|
return getDelegate().getUserById(cached.getId(), realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new UserAdapter(cached, this, session, realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UserModel cacheUser(RealmModel realm, UserModel delegate, Long revision) {
|
||||||
|
StorageId storageId = new StorageId(delegate.getId());
|
||||||
|
CachedUser cached = null;
|
||||||
|
if (!storageId.isLocal()) {
|
||||||
|
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel(component);
|
||||||
|
UserStorageProviderModel.CachePolicy policy = model.getCachePolicy();
|
||||||
|
if (policy != null && policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
cached = new CachedUser(revision, realm, delegate);
|
||||||
|
if (policy == null || policy == UserStorageProviderModel.CachePolicy.DEFAULT) {
|
||||||
|
cache.addRevisioned(cached, startupRevision);
|
||||||
|
} else {
|
||||||
|
long lifespan = -1;
|
||||||
|
if (policy == UserStorageProviderModel.CachePolicy.EVICT_DAILY) {
|
||||||
|
if (model.getEvictionHour() > -1 && model.getEvictionMinute() > -1) {
|
||||||
|
lifespan = dailyTimeout(model.getEvictionHour(), model.getEvictionMinute()) - Time.currentTimeMillis();
|
||||||
|
}
|
||||||
|
} else if (policy == UserStorageProviderModel.CachePolicy.EVICT_WEEKLY) {
|
||||||
|
if (model.getEvictionDay() > 0 && model.getEvictionHour() > -1 && model.getEvictionMinute() > -1) {
|
||||||
|
lifespan = weeklyTimeout(model.getEvictionDay(), model.getEvictionHour(), model.getEvictionMinute()) - Time.currentTimeMillis();
|
||||||
|
}
|
||||||
|
} else if (policy == UserStorageProviderModel.CachePolicy.MAX_LIFESPAN) {
|
||||||
|
lifespan = model.getMaxLifespan();
|
||||||
|
}
|
||||||
|
if (lifespan > 0) {
|
||||||
|
cache.addRevisioned(cached, startupRevision, lifespan);
|
||||||
|
} else {
|
||||||
|
cache.addRevisioned(cached, startupRevision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cached = new CachedUser(revision, realm, delegate);
|
||||||
cache.addRevisioned(cached, startupRevision);
|
cache.addRevisioned(cached, startupRevision);
|
||||||
}
|
}
|
||||||
UserAdapter adapter = new UserAdapter(cached, this, session, realm);
|
UserAdapter adapter = new UserAdapter(cached, this, session, realm);
|
||||||
if (!wasCached) {
|
onCache(realm, adapter, delegate);
|
||||||
onCache(realm, adapter, delegate);
|
|
||||||
}
|
|
||||||
return adapter;
|
return adapter;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static long dailyTimeout(int hour, int minute) {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
Calendar cal2 = Calendar.getInstance();
|
||||||
|
cal.setTimeInMillis(Time.currentTimeMillis());
|
||||||
|
cal2.setTimeInMillis(Time.currentTimeMillis());
|
||||||
|
cal2.set(Calendar.HOUR_OF_DAY, hour);
|
||||||
|
cal2.set(Calendar.MINUTE, minute);
|
||||||
|
if (cal2.getTimeInMillis() < cal.getTimeInMillis()) {
|
||||||
|
int add = (24 * 60 * 60 * 1000);
|
||||||
|
cal.add(Calendar.MILLISECOND, add);
|
||||||
|
} else {
|
||||||
|
cal.add(Calendar.MILLISECOND, (int)(cal2.getTimeInMillis() - cal.getTimeInMillis()));
|
||||||
|
}
|
||||||
|
return cal.getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long weeklyTimeout(int day, int hour, int minute) {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
Calendar cal2 = Calendar.getInstance();
|
||||||
|
cal.setTimeInMillis(Time.currentTimeMillis());
|
||||||
|
cal2.setTimeInMillis(Time.currentTimeMillis());
|
||||||
|
cal2.set(Calendar.HOUR_OF_DAY, hour);
|
||||||
|
cal2.set(Calendar.MINUTE, minute);
|
||||||
|
cal2.set(Calendar.DAY_OF_WEEK, day);
|
||||||
|
if (cal2.getTimeInMillis() < cal.getTimeInMillis()) {
|
||||||
|
int add = (7 * 24 * 60 * 60 * 1000);
|
||||||
|
cal2.add(Calendar.MILLISECOND, add);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cal2.getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
private void onCache(RealmModel realm, UserAdapter adapter, UserModel delegate) {
|
private void onCache(RealmModel realm, UserAdapter adapter, UserModel delegate) {
|
||||||
((OnUserCache)getDelegate()).onCache(realm, adapter, delegate);
|
((OnUserCache)getDelegate()).onCache(realm, adapter, delegate);
|
||||||
((OnUserCache)session.userCredentialManager()).onCache(realm, adapter, delegate);
|
((OnUserCache)session.userCredentialManager()).onCache(realm, adapter, delegate);
|
||||||
|
@ -300,12 +414,14 @@ public class UserCacheSession implements UserCache {
|
||||||
UserModel model = getDelegate().getUserByEmail(email, realm);
|
UserModel model = getDelegate().getUserByEmail(email, realm);
|
||||||
if (model == null) return null;
|
if (model == null) return null;
|
||||||
userId = model.getId();
|
userId = model.getId();
|
||||||
query = new UserListQuery(loaded, cacheKey, realm, model.getId());
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
if (invalidations.contains(userId)) return model;
|
if (invalidations.contains(userId)) return model;
|
||||||
if (managedUsers.containsKey(userId)) return managedUsers.get(userId);
|
if (managedUsers.containsKey(userId)) return managedUsers.get(userId);
|
||||||
|
|
||||||
UserAdapter adapter = getUserAdapter(realm, userId, loaded, model);
|
UserModel adapter = getUserAdapter(realm, userId, loaded, model);
|
||||||
|
if (adapter instanceof UserAdapter) {
|
||||||
|
query = new UserListQuery(loaded, cacheKey, realm, model.getId());
|
||||||
|
cache.addRevisioned(query, startupRevision);
|
||||||
|
}
|
||||||
managedUsers.put(userId, adapter);
|
managedUsers.put(userId, adapter);
|
||||||
return adapter;
|
return adapter;
|
||||||
} else {
|
} else {
|
||||||
|
@ -343,12 +459,15 @@ public class UserCacheSession implements UserCache {
|
||||||
UserModel model = getDelegate().getUserByFederatedIdentity(socialLink, realm);
|
UserModel model = getDelegate().getUserByFederatedIdentity(socialLink, realm);
|
||||||
if (model == null) return null;
|
if (model == null) return null;
|
||||||
userId = model.getId();
|
userId = model.getId();
|
||||||
query = new UserListQuery(loaded, cacheKey, realm, userId);
|
|
||||||
cache.addRevisioned(query, startupRevision);
|
|
||||||
if (invalidations.contains(userId)) return model;
|
if (invalidations.contains(userId)) return model;
|
||||||
if (managedUsers.containsKey(userId)) return managedUsers.get(userId);
|
if (managedUsers.containsKey(userId)) return managedUsers.get(userId);
|
||||||
|
|
||||||
UserAdapter adapter = getUserAdapter(realm, userId, loaded, model);
|
UserModel adapter = getUserAdapter(realm, userId, loaded, model);
|
||||||
|
if (adapter instanceof UserAdapter) {
|
||||||
|
query = new UserListQuery(loaded, cacheKey, realm, model.getId());
|
||||||
|
cache.addRevisioned(query, startupRevision);
|
||||||
|
}
|
||||||
|
|
||||||
managedUsers.put(userId, adapter);
|
managedUsers.put(userId, adapter);
|
||||||
return adapter;
|
return adapter;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.keycloak.models.cache.infinispan.entities;
|
package org.keycloak.models.cache.infinispan.entities;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +11,7 @@ import java.io.Serializable;
|
||||||
public class AbstractRevisioned implements Revisioned, Serializable {
|
public class AbstractRevisioned implements Revisioned, Serializable {
|
||||||
private String id;
|
private String id;
|
||||||
private Long revision;
|
private Long revision;
|
||||||
private final long cacheTimestamp = System.currentTimeMillis();
|
private final long cacheTimestamp = Time.currentTimeMillis();
|
||||||
|
|
||||||
public AbstractRevisioned(Long revision, String id) {
|
public AbstractRevisioned(Long revision, String id) {
|
||||||
this.revision = revision;
|
this.revision = revision;
|
||||||
|
|
|
@ -19,7 +19,11 @@ package org.keycloak.models.sessions.infinispan.initializer;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.models.cache.infinispan.UserCacheSession;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,4 +63,31 @@ public class InitializerStateTest {
|
||||||
Assert.assertTrue(segments.contains(i));
|
Assert.assertTrue(segments.contains(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDailyTimeout() throws Exception {
|
||||||
|
Date date = new Date(UserCacheSession.dailyTimeout(10, 30));
|
||||||
|
System.out.println(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date));
|
||||||
|
date = new Date(UserCacheSession.dailyTimeout(17, 45));
|
||||||
|
System.out.println(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date));
|
||||||
|
date = new Date(UserCacheSession.weeklyTimeout(Calendar.MONDAY, 13, 45));
|
||||||
|
System.out.println(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date));
|
||||||
|
date = new Date(UserCacheSession.weeklyTimeout(Calendar.THURSDAY, 13, 45));
|
||||||
|
System.out.println(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date));
|
||||||
|
System.out.println("----");
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.add(Calendar.HOUR, 1);
|
||||||
|
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
||||||
|
int min = cal.get(Calendar.MINUTE);
|
||||||
|
date = new Date(cal.getTimeInMillis());
|
||||||
|
System.out.println(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date));
|
||||||
|
date = new Date(UserCacheSession.dailyTimeout(hour, min));
|
||||||
|
System.out.println(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date));
|
||||||
|
cal = Calendar.getInstance();
|
||||||
|
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
|
||||||
|
date = new Date(cal.getTimeInMillis());
|
||||||
|
System.out.println(DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(date));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -810,6 +810,8 @@ public class ModelToRepresentation {
|
||||||
} else {
|
} else {
|
||||||
config.put(e.getKey(), e.getValue());
|
config.put(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
config.put(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1757,18 +1757,9 @@ public class RepresentationToModel {
|
||||||
component.setSubType(rep.getSubType());
|
component.setSubType(rep.getSubType());
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, ProviderConfigProperty> providerConfiguration = null;
|
|
||||||
if (!internal) {
|
|
||||||
providerConfiguration = ComponentUtil.getComponentConfigProperties(session, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rep.getConfig() != null) {
|
if (rep.getConfig() != null) {
|
||||||
Set<String> keys = new HashSet<>(rep.getConfig().keySet());
|
Set<String> keys = new HashSet<>(rep.getConfig().keySet());
|
||||||
for (String k : keys) {
|
for (String k : keys) {
|
||||||
if (!internal && !providerConfiguration.containsKey(k)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> values = rep.getConfig().get(k);
|
List<String> values = rep.getConfig().get(k);
|
||||||
if (values == null || values.isEmpty() || values.get(0) == null || values.get(0).trim().isEmpty()) {
|
if (values == null || values.isEmpty() || values.get(0) == null || values.get(0).trim().isEmpty()) {
|
||||||
component.getConfig().remove(k);
|
component.getConfig().remove(k);
|
||||||
|
|
|
@ -78,6 +78,10 @@ public class StorageId implements Serializable {
|
||||||
public static boolean isLocalStorage(String userId) {
|
public static boolean isLocalStorage(String userId) {
|
||||||
return new StorageId(userId).getProviderId() == null;
|
return new StorageId(userId).getProviderId() == null;
|
||||||
}
|
}
|
||||||
|
public boolean isLocal() {
|
||||||
|
return getProviderId() == null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
|
|
|
@ -28,6 +28,14 @@ import org.keycloak.component.PrioritizedComponentModel;
|
||||||
*/
|
*/
|
||||||
public class UserStorageProviderModel extends PrioritizedComponentModel {
|
public class UserStorageProviderModel extends PrioritizedComponentModel {
|
||||||
|
|
||||||
|
public static enum CachePolicy {
|
||||||
|
NO_CACHE,
|
||||||
|
DEFAULT,
|
||||||
|
EVICT_DAILY,
|
||||||
|
EVICT_WEEKLY,
|
||||||
|
MAX_LIFESPAN
|
||||||
|
}
|
||||||
|
|
||||||
public UserStorageProviderModel() {
|
public UserStorageProviderModel() {
|
||||||
setProviderType(UserStorageProvider.class.getName());
|
setProviderType(UserStorageProvider.class.getName());
|
||||||
}
|
}
|
||||||
|
@ -40,6 +48,104 @@ public class UserStorageProviderModel extends PrioritizedComponentModel {
|
||||||
private transient Integer changedSyncPeriod;
|
private transient Integer changedSyncPeriod;
|
||||||
private transient Integer lastSync;
|
private transient Integer lastSync;
|
||||||
private transient Boolean importEnabled;
|
private transient Boolean importEnabled;
|
||||||
|
private transient CachePolicy cachePolicy;
|
||||||
|
private transient long maxLifespan = -1;
|
||||||
|
private transient int evictionHour = -1;
|
||||||
|
private transient int evictionMinute = -1;
|
||||||
|
private transient int evictionDay = -1;
|
||||||
|
private transient long cacheInvalidBefore = -1;
|
||||||
|
|
||||||
|
public CachePolicy getCachePolicy() {
|
||||||
|
if (cachePolicy == null) {
|
||||||
|
String str = getConfig().getFirst("cachePolicy");
|
||||||
|
if (str == null) return null;
|
||||||
|
cachePolicy = CachePolicy.valueOf(str);
|
||||||
|
}
|
||||||
|
return cachePolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCachePolicy(CachePolicy cachePolicy) {
|
||||||
|
this.cachePolicy = cachePolicy;
|
||||||
|
if (cachePolicy == null) {
|
||||||
|
getConfig().remove("cachePolicy");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
getConfig().putSingle("cachePolicy", cachePolicy.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxLifespan() {
|
||||||
|
if (maxLifespan < 0) {
|
||||||
|
String str = getConfig().getFirst("maxLifespan");
|
||||||
|
if (str == null) return -1;
|
||||||
|
maxLifespan = Long.valueOf(str);
|
||||||
|
}
|
||||||
|
return maxLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxLifespan(long maxLifespan) {
|
||||||
|
this.maxLifespan = maxLifespan;
|
||||||
|
getConfig().putSingle("maxLifespan", Long.toString(maxLifespan));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEvictionHour() {
|
||||||
|
if (evictionHour < 0) {
|
||||||
|
String str = getConfig().getFirst("evictionHour");
|
||||||
|
if (str == null) return -1;
|
||||||
|
evictionHour = Integer.valueOf(str);
|
||||||
|
}
|
||||||
|
return evictionHour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvictionHour(int evictionHour) {
|
||||||
|
if (evictionHour > 23 || evictionHour < 0) throw new IllegalArgumentException("Must be between 0 and 23");
|
||||||
|
this.evictionHour = evictionHour;
|
||||||
|
getConfig().putSingle("evictionHour", Integer.toString(evictionHour));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEvictionMinute() {
|
||||||
|
if (evictionMinute < 0) {
|
||||||
|
String str = getConfig().getFirst("evictionMinute");
|
||||||
|
if (str == null) return -1;
|
||||||
|
evictionMinute = Integer.valueOf(str);
|
||||||
|
}
|
||||||
|
return evictionMinute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvictionMinute(int evictionMinute) {
|
||||||
|
if (evictionMinute > 59 || evictionMinute < 0) throw new IllegalArgumentException("Must be between 0 and 59");
|
||||||
|
this.evictionMinute = evictionMinute;
|
||||||
|
getConfig().putSingle("evictionMinute", Integer.toString(evictionMinute));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEvictionDay() {
|
||||||
|
if (evictionDay < 0) {
|
||||||
|
String str = getConfig().getFirst("evictionDay");
|
||||||
|
if (str == null) return -1;
|
||||||
|
evictionDay = Integer.valueOf(str);
|
||||||
|
}
|
||||||
|
return evictionDay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvictionDay(int evictionDay) {
|
||||||
|
if (evictionDay > 7 || evictionDay < 1) throw new IllegalArgumentException("Must be between 1 and 7");
|
||||||
|
this.evictionDay = evictionDay;
|
||||||
|
getConfig().putSingle("evictionDay", Integer.toString(evictionDay));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCacheInvalidBefore() {
|
||||||
|
if (cacheInvalidBefore < 0) {
|
||||||
|
String str = getConfig().getFirst("cacheInvalidBefore");
|
||||||
|
if (str == null) return -1;
|
||||||
|
cacheInvalidBefore = Long.valueOf(str);
|
||||||
|
}
|
||||||
|
return cacheInvalidBefore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheInvalidBefore(long cacheInvalidBefore) {
|
||||||
|
this.cacheInvalidBefore = cacheInvalidBefore;
|
||||||
|
getConfig().putSingle("cacheInvalidBefore", Long.toString(cacheInvalidBefore));
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isImportEnabled() {
|
public boolean isImportEnabled() {
|
||||||
if (importEnabled == null) {
|
if (importEnabled == null) {
|
||||||
|
@ -54,6 +160,8 @@ public class UserStorageProviderModel extends PrioritizedComponentModel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setImportEnabled(boolean flag) {
|
public void setImportEnabled(boolean flag) {
|
||||||
importEnabled = flag;
|
importEnabled = flag;
|
||||||
getConfig().putSingle("importEnabled", Boolean.toString(flag));
|
getConfig().putSingle("importEnabled", Boolean.toString(flag));
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.keycloak.services.resources.admin;
|
package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
|
@ -88,6 +89,7 @@ public class ComponentResource {
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent, @QueryParam("type") String type) {
|
public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent, @QueryParam("type") String type) {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
List<ComponentModel> components = Collections.EMPTY_LIST;
|
List<ComponentModel> components = Collections.EMPTY_LIST;
|
||||||
|
@ -129,13 +131,15 @@ public class ComponentResource {
|
||||||
@GET
|
@GET
|
||||||
@Path("{id}")
|
@Path("{id}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
public ComponentRepresentation getComponent(@PathParam("id") String id) {
|
public ComponentRepresentation getComponent(@PathParam("id") String id) {
|
||||||
auth.requireManage();
|
auth.requireManage();
|
||||||
ComponentModel model = realm.getComponent(id);
|
ComponentModel model = realm.getComponent(id);
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
throw new NotFoundException("Could not find component");
|
throw new NotFoundException("Could not find component");
|
||||||
}
|
}
|
||||||
return ModelToRepresentation.toRepresentation(session, model, false);
|
ComponentRepresentation rep = ModelToRepresentation.toRepresentation(session, model, false);
|
||||||
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
|
|
|
@ -16,11 +16,13 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.federation.storage;
|
package org.keycloak.testsuite.federation.storage;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.GroupModel;
|
import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
@ -28,6 +30,7 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.cache.CachedUserModel;
|
||||||
import org.keycloak.models.cache.infinispan.UserAdapter;
|
import org.keycloak.models.cache.infinispan.UserAdapter;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.storage.StorageId;
|
import org.keycloak.storage.StorageId;
|
||||||
|
@ -40,6 +43,7 @@ import org.keycloak.testsuite.rule.WebResource;
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
import org.keycloak.testsuite.rule.WebRule;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -122,6 +126,126 @@ public class UserStorageTest {
|
||||||
loginBadPassword("tbrady");
|
loginBadPassword("tbrady");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void resetTimeoffset() {
|
||||||
|
Time.setOffset(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIDE() throws Exception {
|
||||||
|
Thread.sleep(100000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDailyEviction() {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.add(Calendar.HOUR, 1);
|
||||||
|
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
||||||
|
int min = cal.get(Calendar.MINUTE);
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel(writableProvider);
|
||||||
|
model.setCachePolicy(UserStorageProviderModel.CachePolicy.EVICT_DAILY);
|
||||||
|
model.setEvictionHour(cal.get(Calendar.HOUR_OF_DAY));
|
||||||
|
model.setEvictionMinute(cal.get(Calendar.MINUTE));
|
||||||
|
|
||||||
|
KeycloakSession session = keycloakRule.startSession();
|
||||||
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
|
CachedUserModel thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
||||||
|
long thorTimestamp = thor.getCacheTimestamp();
|
||||||
|
realm.updateComponent(model);
|
||||||
|
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);
|
||||||
|
model.getConfig().remove("cachePolicy");
|
||||||
|
model.getConfig().remove("evictionHour");
|
||||||
|
model.getConfig().remove("evictionMinute");
|
||||||
|
realm.updateComponent(model);
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWeeklyEviction() {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
|
||||||
|
// sets day of the week to 4 days from now
|
||||||
|
cal.add(Calendar.HOUR, 4 * 24);
|
||||||
|
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel(writableProvider);
|
||||||
|
model.setCachePolicy(UserStorageProviderModel.CachePolicy.EVICT_WEEKLY);
|
||||||
|
model.setEvictionDay(cal.get(Calendar.DAY_OF_WEEK));
|
||||||
|
model.setEvictionHour(cal.get(Calendar.HOUR_OF_DAY));
|
||||||
|
model.setEvictionMinute(cal.get(Calendar.MINUTE));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
model.getConfig().remove("cachePolicy");
|
||||||
|
model.getConfig().remove("evictionHour");
|
||||||
|
model.getConfig().remove("evictionMinute");
|
||||||
|
model.getConfig().remove("evictionDay");
|
||||||
|
realm.updateComponent(model);
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoCache() {
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel(writableProvider);
|
||||||
|
model.setCachePolicy(UserStorageProviderModel.CachePolicy.NO_CACHE);
|
||||||
|
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");
|
||||||
|
// test still
|
||||||
|
UserModel thor2 = session.users().getUserByUsername("thor", realm);
|
||||||
|
Assert.assertFalse(thor2 instanceof CachedUserModel);
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
|
||||||
|
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("evictionHour");
|
||||||
|
model.getConfig().remove("evictionMinute");
|
||||||
|
model.getConfig().remove("evictionDay");
|
||||||
|
realm.updateComponent(model);
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
|
||||||
|
session = keycloakRule.startSession();
|
||||||
|
realm = session.realms().getRealmByName("test");
|
||||||
|
thor = (CachedUserModel)session.users().getUserByUsername("thor", realm);
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdate() {
|
public void testUpdate() {
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
KeycloakSession session = keycloakRule.startSession();
|
||||||
|
|
|
@ -1179,3 +1179,30 @@ add-keystore=Add Keystore
|
||||||
add-keystore.placeholder=Add keystore...
|
add-keystore.placeholder=Add keystore...
|
||||||
view=View
|
view=View
|
||||||
active=Active
|
active=Active
|
||||||
|
|
||||||
|
Sunday=Sunday
|
||||||
|
Monday=Monday
|
||||||
|
Tuesday=Tuesday
|
||||||
|
Wednesday=Wednesday
|
||||||
|
Thursday=Thursday
|
||||||
|
Friday=Friday
|
||||||
|
Saturday=Saturday
|
||||||
|
|
||||||
|
user-strage-cache=Cache Settings
|
||||||
|
userStorage.cachePolicy=Cache Policy
|
||||||
|
userStorage.cachePolicy.option.DEFAULT=DEFAULT
|
||||||
|
userStorage.cachePolicy.option.EVICT_WEEKLY=EVICT_WEEKLY
|
||||||
|
userStorage.cachePolicy.option.EVICT_DAILY=EVICT_DAILY
|
||||||
|
userStorage.cachePolicy.option.MAX_LIFESPAN=MAX_LIFESPAN
|
||||||
|
userStorage.cachePolicy.option.NO_CACHE=NO_CACHE
|
||||||
|
userStorage.cachePolicy.tooltip=Cache Policy for this storage provider. 'DEFAULT' is whatever the default settings are for the global user cache. 'EVICT_DAILY' is a time of day every day that the user cache will be invalidated. 'EVICT_WEEKLY' is a day of the week and time the cache will be invalidated. 'MAX-LIFESPAN' is the time in milliseconds that will be the lifespan of a cache entry.
|
||||||
|
userStorage.cachePolicy.evictionDay=Eviction Day
|
||||||
|
userStorage.cachePolicy.evictionDay.tooltip=Day of the week the entry will become invalid on
|
||||||
|
userStorage.cachePolicy.evictionHour=Eviction Hour
|
||||||
|
userStorage.cachePolicy.evictionHour.tooltip=Hour of day the entry will become invalid on.
|
||||||
|
userStorage.cachePolicy.evictionMinute=Eviction Minute
|
||||||
|
userStorage.cachePolicy.evictionMinute.tooltip=Minute of day the entry will become invalid on.
|
||||||
|
userStorage.cachePolicy.maxLifespan=Max Lifespan
|
||||||
|
userStorage.cachePolicy.maxLifespan.tooltip=Max lifespan of a user cache entry in milliseconds.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -653,6 +653,9 @@ module.controller('UserFederationCtrl', function($scope, $location, $route, real
|
||||||
if (instance.isUserFederationProvider) {
|
if (instance.isUserFederationProvider) {
|
||||||
return instance.priority;
|
return instance.priority;
|
||||||
} else {
|
} else {
|
||||||
|
if (!instance.config['priority']) {
|
||||||
|
console.log('getInstancePriority is undefined');
|
||||||
|
}
|
||||||
return instance.config['priority'][0];
|
return instance.config['priority'][0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -740,6 +743,12 @@ module.controller('GenericUserStorageCtrl', function($scope, $location, Notifica
|
||||||
if (providerFactory.metadata.synchronizable) {
|
if (providerFactory.metadata.synchronizable) {
|
||||||
instance.config['fullSyncPeriod'] = ['-1'];
|
instance.config['fullSyncPeriod'] = ['-1'];
|
||||||
instance.config['changedSyncPeriod'] = ['-1'];
|
instance.config['changedSyncPeriod'] = ['-1'];
|
||||||
|
instance.config['cachePolicy'] = ['DEFAULT'];
|
||||||
|
instance.config['evictionDay'] = [''];
|
||||||
|
instance.config['evictionHour'] = [''];
|
||||||
|
instance.config['evictionMinute'] = [''];
|
||||||
|
instance.config['maxLifespan'] = [''];
|
||||||
|
|
||||||
}
|
}
|
||||||
if (providerFactory.properties) {
|
if (providerFactory.properties) {
|
||||||
|
|
||||||
|
@ -769,6 +778,27 @@ module.controller('GenericUserStorageCtrl', function($scope, $location, Notifica
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!instance.config['cachePolicy']) {
|
||||||
|
instance.config['cachePolicy'] = ['DEFAULT'];
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!instance.config['evictionDay']) {
|
||||||
|
instance.config['evictionDay'] = [''];
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!instance.config['evictionHour']) {
|
||||||
|
instance.config['evictionHour'] = [''];
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!instance.config['evictionMinute']) {
|
||||||
|
instance.config['evictionMinute'] = [''];
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!instance.config['maxLifespan']) {
|
||||||
|
instance.config['maxLifespan'] = [''];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
console.log('Manage instance');
|
console.log('Manage instance');
|
||||||
console.log(instance.name);
|
console.log(instance.name);
|
||||||
|
|
|
@ -68,6 +68,153 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend><span class="text">{{:: 'user-storage-cache-policy' | translate}}</span></legend>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="cachePolicy" class="col-md-2 control-label">{{:: 'userStorage.cachePolicy' | translate}}</label>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div>
|
||||||
|
<select id="cachePolicy" ng-model="instance.config['cachePolicy'][0]" class="form-control">
|
||||||
|
<option value="DEFAULT">{{:: 'userStorage.cachePolicy.option.DEFAULT' | translate}}</option>
|
||||||
|
<option value="EVICT_DAILY">{{:: 'userStorage.cachePolicy.option.EVICT_DAILY' | translate}}</option>
|
||||||
|
<option value="EVICT_WEEKLY">{{:: 'userStorage.cachePolicy.option.EVICT_WEEKLY' | translate}}</option>
|
||||||
|
<option value="MAX_LIFESPAN">{{:: 'userStorage.cachePolicy.option.MAX_LIFESPAN' | translate}}</option>
|
||||||
|
<option value="NO_CACHE">{{:: 'userStorage.cachePolicy.option.NO_CACHE' | translate}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'userStorage.cachePolicy.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-show="instance.config['cachePolicy'][0] == 'EVICT_WEEKLY'">
|
||||||
|
<label for="evictionDay" class="col-md-2 control-label">{{:: 'userStorage.evictionDay' | translate}}</label>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div>
|
||||||
|
<select id="evictionDay" ng-model="instance.config['evictionDay'][0]" class="form-control">
|
||||||
|
<option value="1">{{:: 'Sunday' | translate}}</option>
|
||||||
|
<option value="2">{{:: 'Monday' | translate}}</option>
|
||||||
|
<option value="3">{{:: 'Tuesday' | translate}}</option>
|
||||||
|
<option value="4">{{:: 'Wednesday' | translate}}</option>
|
||||||
|
<option value="5">{{:: 'Thursday' | translate}}</option>
|
||||||
|
<option value="6">{{:: 'Friday' | translate}}</option>
|
||||||
|
<option value="7">{{:: 'Saturday' | translate}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'userStorage.cachePolicy.evictionDay.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix" data-ng-show="instance.config['cachePolicy'][0] == 'EVICT_WEEKLY' || instance.config['cachePolicy'][0] == 'EVICT_DAILY'">
|
||||||
|
<label class="col-md-2 control-label" for="evictionHour">{{:: 'userStorage.cachePolicy.evictionHour' | translate}}</label>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div>
|
||||||
|
<select id="evictionHour" ng-model="instance.config['evictionHour'][0]" class="form-control">
|
||||||
|
<option value="0">00</option>
|
||||||
|
<option value="1">01</option>
|
||||||
|
<option value="2">02</option>
|
||||||
|
<option value="3">03</option>
|
||||||
|
<option value="4">04</option>
|
||||||
|
<option value="5">05</option>
|
||||||
|
<option value="6">06</option>
|
||||||
|
<option value="7">07</option>
|
||||||
|
<option value="8">08</option>
|
||||||
|
<option value="9">09</option>
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="11">11</option>
|
||||||
|
<option value="12">12</option>
|
||||||
|
<option value="13">13</option>
|
||||||
|
<option value="14">14</option>
|
||||||
|
<option value="15">15</option>
|
||||||
|
<option value="16">16</option>
|
||||||
|
<option value="17">17</option>
|
||||||
|
<option value="18">18</option>
|
||||||
|
<option value="19">19</option>
|
||||||
|
<option value="20">20</option>
|
||||||
|
<option value="21">21</option>
|
||||||
|
<option value="22">22</option>
|
||||||
|
<option value="23">23</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'userStorage.cachePolicy.evictionHour.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix" data-ng-show="instance.config['cachePolicy'][0] == 'EVICT_WEEKLY' || instance.config['cachePolicy'][0] == 'EVICT_DAILY'">
|
||||||
|
<label class="col-md-2 control-label" for="evictionMinute">{{:: 'userStorage.cachePolicy.evictionMinute' | translate}}</label>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<div>
|
||||||
|
<select id="evictionMinute" ng-model="instance.config['evictionMinute'][0]" class="form-control">
|
||||||
|
<option value="0">00</option>
|
||||||
|
<option value="1">01</option>
|
||||||
|
<option value="2">02</option>
|
||||||
|
<option value="3">03</option>
|
||||||
|
<option value="4">04</option>
|
||||||
|
<option value="5">05</option>
|
||||||
|
<option value="6">06</option>
|
||||||
|
<option value="7">07</option>
|
||||||
|
<option value="8">08</option>
|
||||||
|
<option value="9">09</option>
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="11">11</option>
|
||||||
|
<option value="12">12</option>
|
||||||
|
<option value="13">13</option>
|
||||||
|
<option value="14">14</option>
|
||||||
|
<option value="15">15</option>
|
||||||
|
<option value="16">16</option>
|
||||||
|
<option value="17">17</option>
|
||||||
|
<option value="18">18</option>
|
||||||
|
<option value="19">19</option>
|
||||||
|
<option value="20">20</option>
|
||||||
|
<option value="21">21</option>
|
||||||
|
<option value="22">22</option>
|
||||||
|
<option value="23">23</option>
|
||||||
|
<option value="24">24</option>
|
||||||
|
<option value="25">25</option>
|
||||||
|
<option value="26">26</option>
|
||||||
|
<option value="27">27</option>
|
||||||
|
<option value="28">28</option>
|
||||||
|
<option value="29">29</option>
|
||||||
|
<option value="30">30</option>
|
||||||
|
<option value="31">31</option>
|
||||||
|
<option value="32">32</option>
|
||||||
|
<option value="33">33</option>
|
||||||
|
<option value="34">34</option>
|
||||||
|
<option value="35">35</option>
|
||||||
|
<option value="36">36</option>
|
||||||
|
<option value="37">37</option>
|
||||||
|
<option value="38">38</option>
|
||||||
|
<option value="39">39</option>
|
||||||
|
<option value="40">40</option>
|
||||||
|
<option value="41">41</option>
|
||||||
|
<option value="42">42</option>
|
||||||
|
<option value="43">43</option>
|
||||||
|
<option value="44">44</option>
|
||||||
|
<option value="45">45</option>
|
||||||
|
<option value="46">46</option>
|
||||||
|
<option value="47">47</option>
|
||||||
|
<option value="48">48</option>
|
||||||
|
<option value="49">49</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="51">51</option>
|
||||||
|
<option value="52">52</option>
|
||||||
|
<option value="53">53</option>
|
||||||
|
<option value="54">54</option>
|
||||||
|
<option value="55">55</option>
|
||||||
|
<option value="56">56</option>
|
||||||
|
<option value="57">57</option>
|
||||||
|
<option value="58">58</option>
|
||||||
|
<option value="59">59</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'userStorage.cachePolicy.evictionMinute.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix" data-ng-show="instance.config['cachePolicy'][0] == 'MAX_LIFESPAN'">
|
||||||
|
<label class="col-md-2 control-label" for="maxLifespan">{{:: 'userStorage.cachePolicy.maxLifespan' | translate}}</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input class="form-control" type="text" ng-model="instance.config['maxLifespan'][0]" id="maxLifespan" />
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'userStorage.cachePolicy.maxLifespan.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-10 col-md-offset-2" data-ng-show="create && access.manageUsers">
|
<div class="col-md-10 col-md-offset-2" data-ng-show="create && access.manageUsers">
|
||||||
<button kc-save>{{:: 'save' | translate}}</button>
|
<button kc-save>{{:: 'save' | translate}}</button>
|
||||||
|
|
Loading…
Reference in a new issue