Add optional, but on by default, check to ensure that IdP session cookie comes from...
[java-idp.git] / src / main / java / edu / internet2 / middleware / shibboleth / idp / session / impl / SessionManagerImpl.java
index 68cdead..fe6da01 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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.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;
 
@@ -65,6 +80,12 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
         sessionStore = storageService;
         partition = "session";
         sessionLifetime = lifetime;
+
+        try {
+            secretKeyGen = KeyGenerator.getInstance("AES");
+        } catch (NoSuchAlgorithmException e) {
+            log.error("AES key generation is not supported", e);
+        }
     }
 
     /**
@@ -86,8 +107,20 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
     }
 
     /** {@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} */
@@ -98,13 +131,11 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
         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;
     }
 
@@ -114,10 +145,7 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
             return;
         }
 
-        SessionManagerEntry sessionEntry = sessionStore.get(partition, sessionID);
-        if (sessionEntry != null) {
-            appCtx.publishEvent(new LogoutEvent(sessionEntry.getSession()));
-        }
+        sessionStore.remove(partition, sessionID);
     }
 
     /** {@inheritDoc} */
@@ -140,22 +168,71 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
     }
 
     /** {@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;
@@ -163,14 +240,19 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
         /**
          * 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;
         }
 
         /**
@@ -191,9 +273,13 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
             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} */
@@ -203,7 +289,7 @@ public class SessionManagerImpl implements SessionManager<Session>, ApplicationC
 
         /** {@inheritDoc} */
         public void onExpire() {
-            sessionManager.destroySession(userSession.getSessionID());
+
         }
     }
 }
\ No newline at end of file