/*
- * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
+ * Copyright 2007 University Corporation for Advanced Internet Development, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package edu.internet2.middleware.shibboleth.idp.session.impl;
+import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.util.List;
+import java.util.Vector;
+
+import javax.crypto.KeyGenerator;
import org.apache.commons.ssl.util.Hex;
-import org.apache.log4j.MDC;
import org.joda.time.DateTime;
import org.opensaml.util.storage.ExpiringObject;
import org.opensaml.util.storage.StorageService;
import org.opensaml.xml.util.DatatypeHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
import edu.internet2.middleware.shibboleth.common.session.LoginEvent;
import edu.internet2.middleware.shibboleth.common.session.LogoutEvent;
import edu.internet2.middleware.shibboleth.common.session.SessionManager;
+import edu.internet2.middleware.shibboleth.common.util.EventingMapBasedStorageService.AddEntryEvent;
+import edu.internet2.middleware.shibboleth.common.util.EventingMapBasedStorageService.RemoveEntryEvent;
import edu.internet2.middleware.shibboleth.idp.session.Session;
-/**
- * Manager of IdP sessions.
- */
-public class SessionManagerImpl implements SessionManager<Session>, ApplicationContextAware {
+/** Manager of IdP sessions. */
+public class SessionManagerImpl implements SessionManager<Session>, ApplicationContextAware, ApplicationListener {
+
+ /** Class logger. */
+ private final Logger log = LoggerFactory.getLogger(SessionManagerImpl.class);
/** Spring context used to publish login and logout events. */
private ApplicationContext appCtx;
+ /** Generator used to create secret keys associated with the session. */
+ private KeyGenerator secretKeyGen;
+
/** Number of random bits within a session ID. */
private final int sessionIDSize = 32;
sessionStore = storageService;
partition = "session";
sessionLifetime = lifetime;
+
+ try {
+ secretKeyGen = KeyGenerator.getInstance("AES");
+ } catch (NoSuchAlgorithmException e) {
+ log.error("AES key generation is not supported", e);
+ }
}
/**
}
/** {@inheritDoc} */
- public void setApplicationContext(ApplicationContext applicationContext) {
- appCtx = applicationContext;
+ public Session createSession() {
+ // generate a random session ID
+ byte[] sid = new byte[sessionIDSize];
+ prng.nextBytes(sid);
+ String sessionID = Hex.encode(sid);
+
+ Session session = new SessionImpl(sessionID, secretKeyGen.generateKey(), sessionLifetime);
+ SessionManagerEntry sessionEntry = new SessionManagerEntry(session, sessionLifetime);
+ sessionStore.put(partition, sessionID, sessionEntry);
+
+ MDC.put("idpSessionId", sessionID);
+ log.trace("Created session {}", sessionID);
+ appCtx.publishEvent(new LoginEvent(session));
+ return session;
}
/** {@inheritDoc} */
String sessionID = Hex.encode(sid);
MDC.put("idpSessionId", sessionID);
- MDC.put("principalName", principal);
-
- Session session = new SessionImpl(sessionID, principal, sessionLifetime);
- SessionManagerEntry sessionEntry = new SessionManagerEntry(this, session, sessionLifetime);
+
+ Session session = new SessionImpl(sessionID, secretKeyGen.generateKey(), sessionLifetime);
+ SessionManagerEntry sessionEntry = new SessionManagerEntry(session, sessionLifetime);
sessionStore.put(partition, sessionID, sessionEntry);
- sessionStore.put(partition, principal, sessionEntry);
- appCtx.publishEvent(new LoginEvent(session));
+ log.trace("Created session {}", sessionID);
return session;
}
return;
}
- SessionManagerEntry sessionEntry = sessionStore.get(partition, sessionID);
- if (sessionEntry != null) {
- appCtx.publishEvent(new LogoutEvent(sessionEntry.getSession()));
- }
+ sessionStore.remove(partition, sessionID);
}
/** {@inheritDoc} */
}
/** {@inheritDoc} */
- public Session getSessionByPrincipalName(String name) {
+ public boolean indexSession(Session session, String index) {
+ if (sessionStore.contains(partition, index)) {
+ return false;
+ }
+
+ SessionManagerEntry sessionEntry = sessionStore.get(partition, session.getSessionID());
+ if (sessionEntry == null) {
+ return false;
+ }
- // TODO
- return null;
+ if (sessionEntry.getSessionIndexes().contains(index)) {
+ return true;
+ }
+
+ sessionEntry.getSessionIndexes().add(index);
+ sessionStore.put(partition, index, sessionEntry);
+ log.trace("Added index {} to session {}", index, session.getSessionID());
+ return true;
}
- /**
- * Session store entry.
- */
+ /** {@inheritDoc} */
+ public void onApplicationEvent(ApplicationEvent event) {
+ if (event instanceof AddEntryEvent) {
+ AddEntryEvent addEvent = (AddEntryEvent) event;
+ if (addEvent.getValue() instanceof SessionManagerEntry) {
+ SessionManagerEntry sessionEntry = (SessionManagerEntry) addEvent.getValue();
+ appCtx.publishEvent(new LoginEvent(sessionEntry.getSession()));
+ }
+ }
+
+ if (event instanceof RemoveEntryEvent) {
+ RemoveEntryEvent removeEvent = (RemoveEntryEvent) event;
+ if (removeEvent.getValue() instanceof SessionManagerEntry) {
+ SessionManagerEntry sessionEntry = (SessionManagerEntry) removeEvent.getValue();
+ appCtx.publishEvent(new LogoutEvent(sessionEntry.getSession()));
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void removeSessionIndex(String index) {
+ SessionManagerEntry sessionEntry = sessionStore.remove(partition, index);
+ if (sessionEntry != null) {
+ log.trace("Removing index {} for session {}", index, sessionEntry.getSessionId());
+ sessionEntry.getSessionIndexes().remove(index);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void setApplicationContext(ApplicationContext applicationContext) {
+ ApplicationContext rootContext = applicationContext;
+ while (rootContext.getParent() != null) {
+ rootContext = rootContext.getParent();
+ }
+ appCtx = rootContext;
+ }
+
+ /** Session store entry. */
public class SessionManagerEntry implements ExpiringObject {
/** User's session. */
private Session userSession;
- /** Manager that owns the session. */
- private SessionManager<Session> sessionManager;
+ /** Indexes for this session. */
+ private List<String> indexes;
/** Time this entry expires. */
private DateTime expirationTime;
/**
* Constructor.
*
- * @param manager manager that owns the session
* @param session user session
* @param lifetime lifetime of session
*/
- public SessionManagerEntry(SessionManager<Session> manager, Session session, long lifetime) {
- sessionManager = manager;
+ public SessionManagerEntry(Session session, long lifetime) {
userSession = session;
expirationTime = new DateTime().plus(lifetime);
+ indexes = new Vector<String>();
+ indexes.add(userSession.getSessionID());
+ }
+
+ /** {@inheritDoc} */
+ public DateTime getExpirationTime() {
+ return expirationTime;
}
/**
return userSession.getSessionID();
}
- /** {@inheritDoc} */
- public DateTime getExpirationTime() {
- return expirationTime;
+ /**
+ * Gets the list of indexes for this session.
+ *
+ * @return list of indexes for this session
+ */
+ public List<String> getSessionIndexes() {
+ return indexes;
}
/** {@inheritDoc} */
/** {@inheritDoc} */
public void onExpire() {
- sessionManager.destroySession(userSession.getSessionID());
+
}
}
}
\ No newline at end of file