1   package com.atlassian.seraph.auth;
2   
3   import org.apache.log4j.Logger;
4   
5   import java.util.Enumeration;
6   import java.util.HashMap;
7   import java.util.List;
8   import java.util.Map;
9   import javax.servlet.http.HttpServletRequest;
10  import javax.servlet.http.HttpSession;
11  
12  /**
13   * Invalidates and performs the manipulation of the session necessary to obtain a fresh JSESSIONID on Tomcat and
14   * the equivalent on other containers. It copies the session content over to a new session with a new id (JSESSIONID)
15   * and can exclude a given list of session attribute keys from the copy.
16   *
17   * See http://jira.atlassian.com/browse/JRA-16008
18   *
19   */
20  class SessionInvalidator
21  {
22      private static final Logger log = Logger.getLogger(SessionInvalidator.class);
23  
24      private final List<String> excludeList;
25  
26      /**
27       * Create a session invalidator configured with the given exclusions.
28       *
29       * @param excludeList a list of session attribute keys to exclude from invalidated sessions.
30       */
31      SessionInvalidator(final List<String> excludeList)
32      {
33          if (excludeList == null)
34          {
35              throw new IllegalArgumentException("excludeList must not be null");
36          }
37          this.excludeList = excludeList;
38      }
39  
40      /**
41       * If there is a session for the given request, invalidate it and create a new session, copying all attributes
42       * over except those configured exclusions.
43       *
44       * @param httpServletRequest the request whose session should be invalidated.
45       */
46      void invalidateSession(HttpServletRequest httpServletRequest)
47      {
48          final HttpSession session = httpServletRequest.getSession(false);
49          if (session != null && !session.isNew())
50          {
51              if (log.isDebugEnabled())
52              {
53                  dumpInfo(httpServletRequest, session);
54              }
55              final Map<String, Object> contents = getSessionContentsToKeep(session);
56              try
57              {
58                  session.invalidate();
59                  final HttpSession newSession = httpServletRequest.getSession(true);
60                  setAll(newSession, contents);
61              }
62              catch (IllegalStateException e)
63              {
64                  log.warn("Couldn't invalidate for request because " + e.getMessage());
65              }
66          }
67      }
68  
69      private static void setAll(final HttpSession dest, final Map<String, Object> source)
70      {
71          for (Map.Entry<String, Object> entry : source.entrySet())
72          {
73              dest.setAttribute(entry.getKey(), entry.getValue());
74          }
75      }
76  
77      private Map<String, Object> getSessionContentsToKeep(final HttpSession session)
78      {
79          Map<String, Object> sessionContents = new HashMap<String, Object>();
80          Enumeration attributes = session.getAttributeNames();
81          while (attributes.hasMoreElements())
82          {
83              String name = (String) attributes.nextElement();
84              if (!excludeList.contains(name))
85              {
86                  sessionContents.put(name, session.getAttribute(name));
87              }
88          }
89          return sessionContents;
90      }
91  
92      ///CLOVER:OFF
93      private void dumpInfo(final HttpServletRequest httpServletRequest, final HttpSession session)
94      {
95          log.debug("invalidating session from request: "
96                  + httpServletRequest.getMethod() + " "
97                  + session.getId() + " "
98                  + httpServletRequest.getRequestURI() + " "
99          );
100 
101         Enumeration attributes = session.getAttributeNames();
102         while (attributes.hasMoreElements())
103         {
104             String name = (String) attributes.nextElement();
105             log.debug("session attribute: " + name);
106         }
107     }
108     ///CLOVER:ON
109 }