/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security.auth;
import java.util.HashSet;
import java.util.Set;
import java.util.TimerTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Logger;
import org.geotools.util.logging.Logging;
import org.springframework.security.core.Authentication;
/**
* An {@link AuthenticationCache} implementation using a {@link LRUCache} for
* caching authentication tokens.
*
* For an explanation of the time parameters, see {@link AuthenticationCacheEntry}
*
* The class uses a {@link ReentrantReadWriteLock} object to synchronize
* access from multiple threads
*
* Additionally, a {@link TimerTask} is started to remove expired entries.
*
* @author christian
*
*/
public class LRUAuthenticationCacheImpl implements AuthenticationCache {
protected LRUCache<AuthenticationCacheKey, AuthenticationCacheEntry> cache;
int timeToIdleSeconds,timeToLiveSeconds,maxEntries;
protected final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
protected final Lock readLock = readWriteLock.readLock();
protected final Lock writeLock = readWriteLock.writeLock();
static Logger LOGGER = Logging.getLogger("org.geoserver.security");
/**
* Timer task to remove unused entries
*
*/
public LRUAuthenticationCacheImpl(int maxEntries) {
this(DEFAULT_IDLE_TIME, DEFAULT_LIVE_TIME, maxEntries);
}
public LRUAuthenticationCacheImpl(int timeToIdleSeconds, int timeToLiveSeconds, int maxEntries) {
super();
this.timeToIdleSeconds = timeToIdleSeconds;
this.timeToLiveSeconds = timeToLiveSeconds;
this.maxEntries = maxEntries;
cache = new LRUCache<AuthenticationCacheKey, AuthenticationCacheEntry>(maxEntries);
}
public int getTimeToIdleSeconds() {
return timeToIdleSeconds;
}
public int getTimeToLiveSeconds() {
return timeToLiveSeconds;
}
public int getMaxEntries() {
return maxEntries;
}
@Override
public void removeAll() {
writeLock.lock();
try {
cache.clear();
} finally {
writeLock.unlock();
}
}
@Override
public void removeAll(String filterName) {
if (filterName==null) return;
writeLock.lock();
try {
Set<AuthenticationCacheKey> toBeRemoved = new HashSet<AuthenticationCacheKey>();
for (AuthenticationCacheKey key: cache.keySet()) {
if(filterName.equals(key.getFilterName()))
toBeRemoved.add(key);
}
for (AuthenticationCacheKey key: toBeRemoved)
cache.remove(key);
} finally {
writeLock.unlock();
}
}
@Override
public void remove(String filterName, String cacheKey) {
writeLock.lock();
try {
cache.remove(new AuthenticationCacheKey(filterName, cacheKey));
} finally {
writeLock.unlock();
}
}
@Override
public Authentication get(String filterName, String cacheKey) {
readLock.lock();
boolean hasTobeRemoved=false;
try {
long currentTime=System.currentTimeMillis();
AuthenticationCacheEntry entry = cache.get(new AuthenticationCacheKey(filterName, cacheKey));
if (entry==null)
return null;
if (entry.hasExpired(currentTime)) {
hasTobeRemoved=true;
return null;
}
entry.setLastAccessed(currentTime);
return entry.getAuthentication();
} finally {
readLock.unlock();
if (hasTobeRemoved)
remove(filterName,cacheKey);
}
}
@Override
public void put(String filterName, String cacheKey, Authentication auth,
Integer timeToIdleSeconds, Integer timeToLiveSeconds) {
timeToIdleSeconds = timeToIdleSeconds != null ? timeToIdleSeconds : this.timeToIdleSeconds;;
timeToLiveSeconds = timeToLiveSeconds != null ? timeToLiveSeconds : this.timeToLiveSeconds;
writeLock.lock();
try {
cache.put(new AuthenticationCacheKey(filterName, cacheKey),
new AuthenticationCacheEntry(auth,
timeToIdleSeconds,
timeToLiveSeconds));
} finally {
writeLock.unlock();
}
}
@Override
public void put(String filterName, String cacheKey, Authentication auth) {
put(filterName,cacheKey,auth,timeToIdleSeconds,timeToLiveSeconds);
}
}