blob: 6d425c29d8bb9844fc7da4d3ed65e808c9c6bf46 [file] [log] [blame]
package de.ids_mannheim.korap.authentication;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.user.DemoUser;
import de.ids_mannheim.korap.utils.ConcurrentMultiMap;
import de.ids_mannheim.korap.utils.TimeUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.joda.time.DateTime;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* session object to hold current user sessions and track inactive
* time to close
* unused sessions. Inactive sessions are not enforced until user
* makes a
* request through thrift
*
* @author hanl
*/
//todo: use simple ehcache!
public class SessionFactory implements Runnable {
private static Logger jlog = LogManager.getLogger(SessionFactory.class);
public static ConcurrentMap<String, TokenContext> sessionsObject;
public static ConcurrentMap<String, DateTime> timeCheck;
public static ConcurrentMultiMap<String, String> loggedInRecord;
// private final ConcurrentMultiMap<String, Long> failedLogins;
private final boolean multipleEnabled;
private final int inactive;
public SessionFactory (boolean multipleEnabled, int inactive) {
jlog.debug("allow multiple sessions per user: "+ multipleEnabled);
this.multipleEnabled = multipleEnabled;
this.inactive = inactive;
this.sessionsObject = new ConcurrentHashMap<>();
this.timeCheck = new ConcurrentHashMap<>();
this.loggedInRecord = new ConcurrentMultiMap<>();
}
public boolean hasSession (TokenContext context) {
if (context.getUsername().equalsIgnoreCase(DemoUser.DEMOUSER_NAME))
return false;
List<String> value = loggedInRecord.get(context.getUsername());
return value != null && !value.isEmpty();
}
// todo: remove this!
@Cacheable("session")
public TokenContext getSession (String token) throws KustvaktException {
jlog.debug("logged in users: "+ loggedInRecord);
TokenContext context = sessionsObject.get(token);
if (context != null) {
// fixme: set context to respecitve expiratin interval and return context. handler checks expiration later!
if (isUserSessionValid(token)) {
resetInterval(token);
}
else
throw new KustvaktException(StatusCodes.EXPIRED);
}
return context;
}
//todo: ?!
@CacheEvict(value = "session", key = "#session.token")
public void putSession (final String token, final TokenContext activeUser)
throws KustvaktException {
if (!hasSession(activeUser) | multipleEnabled) {
loggedInRecord.put(activeUser.getUsername(), token);
sessionsObject.put(token, activeUser);
timeCheck.put(token, TimeUtils.getNow());
}
else {
removeAll(activeUser);
throw new KustvaktException(StatusCodes.ALREADY_LOGGED_IN);
}
}
public void removeAll (final TokenContext activeUser) {
for (String existing : loggedInRecord.get(activeUser.getUsername())) {
timeCheck.remove(existing);
sessionsObject.remove(existing);
}
loggedInRecord.remove(activeUser.getUsername());
}
@CacheEvict(value = "session", key = "#session.token")
public void removeSession (String token) {
String username = sessionsObject.get(token).getUsername();
loggedInRecord.remove(username, token);
if (loggedInRecord.get(username).isEmpty())
loggedInRecord.remove(username);
timeCheck.remove(token);
sessionsObject.remove(token);
}
/**
* reset inactive time interval to 0
*
* @param token
*/
private void resetInterval (String token) {
timeCheck.put(token, TimeUtils.getNow());
}
/**
* if user possesses a valid non-expired session token
*
* @param token
* @return validity of user to request a backend function
*/
private boolean isUserSessionValid (String token) {
if (timeCheck.containsKey(token)) {
if (TimeUtils.plusSeconds(timeCheck.get(token).getMillis(),
inactive).isAfterNow()) {
jlog.debug("user has session");
return true;
}
else
jlog.debug("user with token "+token+" has an invalid session");
}
return false;
}
/**
* clean inactive sessions from session object
* TODO: persist userdata to database when session times out!
*/
private void timeoutMaintenance () {
jlog.trace("running session cleanup thread");
Set<String> inactive = new HashSet<>();
for (Entry<String, DateTime> entry : timeCheck.entrySet()) {
if (!isUserSessionValid(entry.getKey())) {
TokenContext user = sessionsObject.get(entry.getKey());
jlog.trace("removing user session for user "+
user.getUsername());
inactive.add(user.getUsername());
removeSession(entry.getKey());
}
}
// fixme: not doing anything!
if (inactive.size() > 0)
jlog.trace("removing inactive user session for users "+
inactive);
}
/**
* run cleanup-thread
*/
@Override
public void run () {
timeoutMaintenance();
if (loggedInRecord.size() > 0)
jlog.debug("logged users: "+ loggedInRecord.toString());
}
}