Quellcode durchsuchen

SEC-423: Fixed IllegalArguemntException being thrown by checking for null contextFromSessionObject

Vishal Puri vor 18 Jahren
Ursprung
Commit
62c832e366

+ 354 - 300
core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java

@@ -33,323 +33,377 @@ import org.springframework.beans.factory.InitializingBean;
 import org.springframework.util.Assert;
 import org.springframework.util.ReflectionUtils;
 
-
 /**
- * Populates the {@link SecurityContextHolder} with information obtained from the <code>HttpSession</code>.
- *
+ * Populates the {@link SecurityContextHolder} with information obtained from
+ * the <code>HttpSession</code>.
+ * 
  * <p>
- * The <code>HttpSession</code> will be queried to retrieve the <code>SecurityContext</code> that should be
- * stored against the <code>SecurityContextHolder</code> for the duration of the web request. At the end of the web
- * request, any updates made to the <code>SecurityContextHolder</code> will be persisted back to the
+ * The <code>HttpSession</code> will be queried to retrieve the
+ * <code>SecurityContext</code> that should be stored against the
+ * <code>SecurityContextHolder</code> for the duration of the web request. At
+ * the end of the web request, any updates made to the
+ * <code>SecurityContextHolder</code> will be persisted back to the
  * <code>HttpSession</code> by this filter.
  * </p>
  * <p>
- * If a valid <code>SecurityContext</code> cannot be obtained from the <code>HttpSession</code> for whatever
- * reason, a fresh <code>SecurityContext</code> will be created and used instead. The created object will be of the
- * instance defined by the {@link #setContext(Class)} method (which defaults to {@link
+ * If a valid <code>SecurityContext</code> cannot be obtained from the
+ * <code>HttpSession</code> for whatever reason, a fresh
+ * <code>SecurityContext</code> will be created and used instead. The created
+ * object will be of the instance defined by the {@link #setContext(Class)}
+ * method (which defaults to {@link
  * org.acegisecurity.context.SecurityContextImpl}.
  * </p>
  * <p>
- * No <code>HttpSession</code> will be created by this filter if one does not already exist. If at the end of
- * the web request the <code>HttpSession</code> does not exist, a <code>HttpSession</code> will <b>only</b> be created
- * if the current contents of the <code>SecurityContextHolder</code> are not {@link
- * java.lang.Object#equals(java.lang.Object)} to a <code>new</code> instance of {@link #setContext(Class)}. This
- * avoids needless <code>HttpSession</code> creation, but automates the storage of changes made to the
- * <code>SecurityContextHolder</code>. There is one exception to this rule, that is if the {@link
- * #forceEagerSessionCreation} property is <code>true</code>, in which case sessions will always be created
- * irrespective of normal session-minimisation logic (the default is <code>false</code>, as this is resource intensive
- * and not recommended).
+ * No <code>HttpSession</code> will be created by this filter if one does not
+ * already exist. If at the end of the web request the <code>HttpSession</code>
+ * does not exist, a <code>HttpSession</code> will <b>only</b> be created if
+ * the current contents of the <code>SecurityContextHolder</code> are not
+ * {@link java.lang.Object#equals(java.lang.Object)} to a <code>new</code>
+ * instance of {@link #setContext(Class)}. This avoids needless
+ * <code>HttpSession</code> creation, but automates the storage of changes
+ * made to the <code>SecurityContextHolder</code>. There is one exception to
+ * this rule, that is if the {@link #forceEagerSessionCreation} property is
+ * <code>true</code>, in which case sessions will always be created
+ * irrespective of normal session-minimisation logic (the default is
+ * <code>false</code>, as this is resource intensive and not recommended).
  * </p>
  * <p>
- * This filter will only execute once per request, to resolve servlet container (specifically Weblogic)
- * incompatibilities.</p>
+ * This filter will only execute once per request, to resolve servlet container
+ * (specifically Weblogic) incompatibilities.
+ * </p>
  * <p>
- * If for whatever reason no <code>HttpSession</code> should <b>ever</b> be created (eg this filter is only
- * being used with Basic authentication or similar clients that will never present the same <code>jsessionid</code>
- * etc), the {@link #setAllowSessionCreation(boolean)} should be set to <code>false</code>. Only do this if you really
- * need to conserve server memory and ensure all classes using the <code>SecurityContextHolder</code> are designed to
- * have no persistence of the <code>SecurityContext</code> between web requests. Please note that if {@link
- * #forceEagerSessionCreation} is <code>true</code>, the <code>allowSessionCreation</code> must also be
- * <code>true</code> (setting it to <code>false</code> will cause a startup time error).
+ * If for whatever reason no <code>HttpSession</code> should <b>ever</b> be
+ * created (eg this filter is only being used with Basic authentication or
+ * similar clients that will never present the same <code>jsessionid</code>
+ * etc), the {@link #setAllowSessionCreation(boolean)} should be set to
+ * <code>false</code>. Only do this if you really need to conserve server
+ * memory and ensure all classes using the <code>SecurityContextHolder</code>
+ * are designed to have no persistence of the <code>SecurityContext</code>
+ * between web requests. Please note that if {@link #forceEagerSessionCreation}
+ * is <code>true</code>, the <code>allowSessionCreation</code> must also be
+ * <code>true</code> (setting it to <code>false</code> will cause a startup
+ * time error).
  * </p>
  * <p>
- * This filter MUST be executed BEFORE any authentication processing mechanisms. Authentication processing
- * mechanisms (eg BASIC, CAS processing filters etc) expect the <code>SecurityContextHolder</code> to contain a valid
+ * This filter MUST be executed BEFORE any authentication processing mechanisms.
+ * Authentication processing mechanisms (eg BASIC, CAS processing filters etc)
+ * expect the <code>SecurityContextHolder</code> to contain a valid
  * <code>SecurityContext</code> by the time they execute.
  * </p>
- *
+ * 
  * @author Ben Alex
  * @author Patrick Burleson
- * @version $Id$
+ * @version $Id: HttpSessionContextIntegrationFilter.java 1784 2007-02-24
+ * 21:00:24Z luke_t $
  */
 public class HttpSessionContextIntegrationFilter implements InitializingBean, Filter {
-    //~ Static fields/initializers =====================================================================================
-
-    protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class);
-    private static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";
-    public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT";
-
-    //~ Instance fields ================================================================================================
-
-    private Class context = SecurityContextImpl.class;
-    private Object contextObject;
-
-    /**
-     * Indicates if this filter can create a <code>HttpSession</code> if needed (sessions are always created
-     * sparingly, but setting this value to <code>false</code> will prohibit sessions from ever being created).
-     * Defaults to <code>true</code>. Do not set to <code>false</code> if you are have set {@link
-     * #forceEagerSessionCreation} to <code>true</code>, as the properties would be in conflict.
-     */
-    private boolean allowSessionCreation = true;
-
-    /**
-     * Indicates if this filter is required to create a <code>HttpSession</code> for every request before
-     * proceeding through the filter chain, even if the <code>HttpSession</code> would not ordinarily have been
-     * created. By default this is <code>false</code>, which is entirely appropriate for most circumstances as you do
-     * not want a <code>HttpSession</code> created unless the filter actually needs one. It is envisaged the main
-     * situation in which this property would be set to <code>true</code> is if using other filters that depend on a
-     * <code>HttpSession</code> already existing, such as those which need to obtain a session ID. This is only
-     * required in specialised cases, so leave it set to <code>false</code> unless you have an actual requirement and
-     * are conscious of the session creation overhead.
-     */
-    private boolean forceEagerSessionCreation = false;
-
-    /**
-     * Indicates whether the <code>SecurityContext</code> will be cloned from the <code>HttpSession</code>. The
-     * default is to simply reference (ie the default is <code>false</code>). The default may cause issues if
-     * concurrent threads need to have a different security identity from other threads being concurrently processed
-     * that share the same <code>HttpSession</code>. In most normal environments this does not represent an issue,
-     * as changes to the security identity in one thread is allowed to affect the security identitiy in other
-     * threads associated with the same <code>HttpSession</code>. For unusual cases where this is not permitted,
-     * change this value to <code>true</code> and ensure the {@link #context} is set to a <code>SecurityContext</code>
-     * that implements {@link Cloneable} and overrides the <code>clone()</code> method.
-     */
-    private boolean cloneFromHttpSession = false;
-
-    public boolean isCloneFromHttpSession() {
-        return cloneFromHttpSession;
-    }
-
-    public void setCloneFromHttpSession(boolean cloneFromHttpSession) {
-        this.cloneFromHttpSession = cloneFromHttpSession;
-    }
-
-    public HttpSessionContextIntegrationFilter() throws ServletException {
-        this.contextObject = generateNewContext();
-    }
-
-    //~ Methods ========================================================================================================
-
-    public void afterPropertiesSet() throws Exception {
-        if ((this.context == null) || (!SecurityContext.class.isAssignableFrom(this.context))) {
-            throw new IllegalArgumentException(
-                "context must be defined and implement SecurityContext "
-                + "(typically use org.acegisecurity.context.SecurityContextImpl; existing class is "
-                + this.context + ")");
-        }
-
-        if ((forceEagerSessionCreation == true) && (allowSessionCreation == false)) {
-            throw new IllegalArgumentException(
-                "If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
-        }
-    }
-
-    /**
-     * Does nothing. We use IoC container lifecycle services instead.
-     */
-    public void destroy() {}
-
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-        throws IOException, ServletException {
-        if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {
-            // ensure that filter is only applied once per request
-            chain.doFilter(request, response);
-        } else {
-            if (request != null) {
-                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
-            }
-
-            HttpSession httpSession = null;
-            boolean httpSessionExistedAtStartOfRequest = false;
-
-            try {
-                httpSession = ((HttpServletRequest) request).getSession(forceEagerSessionCreation);
-            } catch (IllegalStateException ignored) {}
-
-            if (httpSession != null) {
-                httpSessionExistedAtStartOfRequest = true;
-
-                Object contextFromSessionObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);
-
-                // Clone if required (see SEC-356)
-                if (cloneFromHttpSession) {
-                    Assert.isInstanceOf(Cloneable.class, contextFromSessionObject,
-                            "Context must implement Clonable and provide a Object.clone() method");
-                    try {
-                        Method m = contextFromSessionObject.getClass().getMethod("clone", new Class[] {});
-                        if (!m.isAccessible()) {
-                            m.setAccessible(true);
-                        }
-                        contextFromSessionObject = m.invoke(contextFromSessionObject, new Object[] {});
-                    } catch (Exception ex) {
-                        ReflectionUtils.handleReflectionException(ex);
-                    }
-                }
-
-                if (contextFromSessionObject != null) {
-                    if (contextFromSessionObject instanceof SecurityContext) {
-                        if (logger.isDebugEnabled()) {
-                            logger.debug("Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and "
-                                + "set to SecurityContextHolder: '" + contextFromSessionObject + "'");
-                        }
-
-                        SecurityContextHolder.setContext((SecurityContext) contextFromSessionObject);
-                    } else {
-                        if (logger.isWarnEnabled()) {
-                            logger.warn("ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '"
-                                + contextFromSessionObject
-                                + "'; are you improperly modifying the HttpSession directly "
-                                + "(you should always use SecurityContextHolder) or using the HttpSession attribute "
-                                + "reserved for this class? - new SecurityContext instance associated with "
-                                + "SecurityContextHolder");
-                        }
-
-                        SecurityContextHolder.setContext(generateNewContext());
-                    }
-                } else {
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("HttpSession returned null object for ACEGI_SECURITY_CONTEXT - new "
-                            + "SecurityContext instance associated with SecurityContextHolder");
-                    }
-
-                    SecurityContextHolder.setContext(generateNewContext());
-                }
-            } else {
-                if (logger.isDebugEnabled()) {
-                    logger.debug("No HttpSession currently exists - new SecurityContext instance "
-                        + "associated with SecurityContextHolder");
-                }
-
-                SecurityContextHolder.setContext(generateNewContext());
-            }
-
-            // Make the HttpSession null, as we want to ensure we don't keep
-            // a reference to the HttpSession laying around in case the
-            // chain.doFilter() invalidates it.
-            httpSession = null;
-
-            // Proceed with chain
-            int contextWhenChainProceeded = SecurityContextHolder.getContext().hashCode();
-
-            try {
-                chain.doFilter(request, response);
-            } catch (IOException ioe) {
-                throw ioe;
-            } catch (ServletException se) {
-                throw se;
-            } finally {
-                // do clean up, even if there was an exception
-                // Store context back to HttpSession
-                try {
-                    httpSession = ((HttpServletRequest) request).getSession(false);
-                } catch (IllegalStateException ignored) {}
-
-                if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("HttpSession is now null, but was not null at start of request; "
-                                + "session was invalidated, so do not create a new session");
-                    }
-                }
-
-                // Generate a HttpSession only if we need to
-                if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) {
-                    if (!allowSessionCreation) {
-                        if (logger.isDebugEnabled()) {
-                            logger.debug("The HttpSession is currently null, and the "
-                                   + "HttpSessionContextIntegrationFilter is prohibited from creating an HttpSession "
-                                   + "(because the allowSessionCreation property is false) - SecurityContext thus not "
-                                   + "stored for next request");
-                        }
-                    } else if (!contextObject.equals(SecurityContextHolder.getContext())) {
-                        if (logger.isDebugEnabled()) {
-                            logger.debug("HttpSession being created as SecurityContextHolder contents are non-default");
-                        }
-
-                        try {
-                            httpSession = ((HttpServletRequest) request).getSession(true);
-                        } catch (IllegalStateException ignored) {}
-                    } else {
-                        if (logger.isDebugEnabled()) {
-                            logger.debug(
-                                    "HttpSession is null, but SecurityContextHolder has not changed from default: ' "
-                                    + SecurityContextHolder.getContext()
-                                    + "'; not creating HttpSession or storing SecurityContextHolder contents");
-                        }
-                    }
-                }
-
-                // If HttpSession exists, store current SecurityContextHolder contents but only if SecurityContext has
-                // actually changed (see JIRA SEC-37)
-                if ((httpSession != null)
-                    && (SecurityContextHolder.getContext().hashCode() != contextWhenChainProceeded)) {
-                    httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
-
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("SecurityContext stored to HttpSession: '" + SecurityContextHolder.getContext()
-                            + "'");
-                    }
-                }
-
-                // Remove SecurityContextHolder contents
-                SecurityContextHolder.clearContext();
-
-                if (logger.isDebugEnabled()) {
-                    logger.debug("SecurityContextHolder set to new context, as request processing completed");
-                }
-            }
-        }
-    }
-
-    public SecurityContext generateNewContext() throws ServletException {
-        try {
-            return (SecurityContext) this.context.newInstance();
-        } catch (InstantiationException ie) {
-            throw new ServletException(ie);
-        } catch (IllegalAccessException iae) {
-            throw new ServletException(iae);
-        }
-    }
-
-    public Class getContext() {
-        return context;
-    }
-
-    /**
-     * Does nothing. We use IoC container lifecycle services instead.
-     *
-     * @param filterConfig ignored
-     *
-     * @throws ServletException ignored
-     */
-    public void init(FilterConfig filterConfig) throws ServletException {}
-
-    public boolean isAllowSessionCreation() {
-        return allowSessionCreation;
-    }
-
-    public boolean isForceEagerSessionCreation() {
-        return forceEagerSessionCreation;
-    }
-
-    public void setAllowSessionCreation(boolean allowSessionCreation) {
-        this.allowSessionCreation = allowSessionCreation;
-    }
-
-    public void setContext(Class secureContext) {
-        this.context = secureContext;
-    }
-
-    public void setForceEagerSessionCreation(boolean forceEagerSessionCreation) {
-        this.forceEagerSessionCreation = forceEagerSessionCreation;
-    }
+	// ~ Static fields/initializers
+	// =====================================================================================
+
+	protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class);
+
+	private static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";
+
+	public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT";
+
+	// ~ Instance fields
+	// ================================================================================================
+
+	private Class context = SecurityContextImpl.class;
+
+	private Object contextObject;
+
+	/**
+	 * Indicates if this filter can create a <code>HttpSession</code> if
+	 * needed (sessions are always created sparingly, but setting this value to
+	 * <code>false</code> will prohibit sessions from ever being created).
+	 * Defaults to <code>true</code>. Do not set to <code>false</code> if
+	 * you are have set {@link #forceEagerSessionCreation} to <code>true</code>,
+	 * as the properties would be in conflict.
+	 */
+	private boolean allowSessionCreation = true;
+
+	/**
+	 * Indicates if this filter is required to create a <code>HttpSession</code>
+	 * for every request before proceeding through the filter chain, even if the
+	 * <code>HttpSession</code> would not ordinarily have been created. By
+	 * default this is <code>false</code>, which is entirely appropriate for
+	 * most circumstances as you do not want a <code>HttpSession</code>
+	 * created unless the filter actually needs one. It is envisaged the main
+	 * situation in which this property would be set to <code>true</code> is
+	 * if using other filters that depend on a <code>HttpSession</code>
+	 * already existing, such as those which need to obtain a session ID. This
+	 * is only required in specialised cases, so leave it set to
+	 * <code>false</code> unless you have an actual requirement and are
+	 * conscious of the session creation overhead.
+	 */
+	private boolean forceEagerSessionCreation = false;
+
+	/**
+	 * Indicates whether the <code>SecurityContext</code> will be cloned from
+	 * the <code>HttpSession</code>. The default is to simply reference (ie
+	 * the default is <code>false</code>). The default may cause issues if
+	 * concurrent threads need to have a different security identity from other
+	 * threads being concurrently processed that share the same
+	 * <code>HttpSession</code>. In most normal environments this does not
+	 * represent an issue, as changes to the security identity in one thread is
+	 * allowed to affect the security identitiy in other threads associated with
+	 * the same <code>HttpSession</code>. For unusual cases where this is not
+	 * permitted, change this value to <code>true</code> and ensure the
+	 * {@link #context} is set to a <code>SecurityContext</code> that
+	 * implements {@link Cloneable} and overrides the <code>clone()</code>
+	 * method.
+	 */
+	private boolean cloneFromHttpSession = false;
+
+	public boolean isCloneFromHttpSession() {
+		return cloneFromHttpSession;
+	}
+
+	public void setCloneFromHttpSession(boolean cloneFromHttpSession) {
+		this.cloneFromHttpSession = cloneFromHttpSession;
+	}
+
+	public HttpSessionContextIntegrationFilter() throws ServletException {
+		this.contextObject = generateNewContext();
+	}
+
+	// ~ Methods
+	// ========================================================================================================
+
+	public void afterPropertiesSet() throws Exception {
+		if ((this.context == null) || (!SecurityContext.class.isAssignableFrom(this.context))) {
+			throw new IllegalArgumentException("context must be defined and implement SecurityContext "
+					+ "(typically use org.acegisecurity.context.SecurityContextImpl; existing class is " + this.context
+					+ ")");
+		}
+
+		if ((forceEagerSessionCreation == true) && (allowSessionCreation == false)) {
+			throw new IllegalArgumentException(
+					"If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
+		}
+	}
+
+	/**
+	 * Does nothing. We use IoC container lifecycle services instead.
+	 */
+	public void destroy() {
+	}
+
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
+			ServletException {
+		if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {
+			// ensure that filter is only applied once per request
+			chain.doFilter(request, response);
+		}
+		else {
+			if (request != null) {
+				request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
+			}
+
+			HttpSession httpSession = null;
+			boolean httpSessionExistedAtStartOfRequest = false;
+
+			try {
+				httpSession = ((HttpServletRequest) request).getSession(forceEagerSessionCreation);
+			}
+			catch (IllegalStateException ignored) {
+			}
+
+			if (httpSession != null) {
+				httpSessionExistedAtStartOfRequest = true;
+
+				Object contextFromSessionObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);
+
+				if (contextFromSessionObject != null) {
+					// Clone if required (see SEC-356)
+					if (cloneFromHttpSession) {
+						Assert.isInstanceOf(Cloneable.class, contextFromSessionObject,
+								"Context must implement Clonable and provide a Object.clone() method");
+						try {
+							Method m = contextFromSessionObject.getClass().getMethod("clone", new Class[] {});
+							if (!m.isAccessible()) {
+								m.setAccessible(true);
+							}
+							contextFromSessionObject = m.invoke(contextFromSessionObject, new Object[] {});
+						}
+						catch (Exception ex) {
+							ReflectionUtils.handleReflectionException(ex);
+						}
+					}
+
+					if (contextFromSessionObject instanceof SecurityContext) {
+						if (logger.isDebugEnabled()) {
+							logger.debug("Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and "
+									+ "set to SecurityContextHolder: '" + contextFromSessionObject + "'");
+						}
+
+						SecurityContextHolder.setContext((SecurityContext) contextFromSessionObject);
+					}
+					else {
+						if (logger.isWarnEnabled()) {
+							logger
+									.warn("ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '"
+											+ contextFromSessionObject
+											+ "'; are you improperly modifying the HttpSession directly "
+											+ "(you should always use SecurityContextHolder) or using the HttpSession attribute "
+											+ "reserved for this class? - new SecurityContext instance associated with "
+											+ "SecurityContextHolder");
+						}
+
+						SecurityContextHolder.setContext(generateNewContext());
+					}
+				}
+				else {
+					if (logger.isDebugEnabled()) {
+						logger.debug("HttpSession returned null object for ACEGI_SECURITY_CONTEXT - new "
+								+ "SecurityContext instance associated with SecurityContextHolder");
+					}
+
+					SecurityContextHolder.setContext(generateNewContext());
+				}
+			}
+			else {
+				if (logger.isDebugEnabled()) {
+					logger.debug("No HttpSession currently exists - new SecurityContext instance "
+							+ "associated with SecurityContextHolder");
+				}
+
+				SecurityContextHolder.setContext(generateNewContext());
+			}
+
+			// Make the HttpSession null, as we want to ensure we don't keep
+			// a reference to the HttpSession laying around in case the
+			// chain.doFilter() invalidates it.
+			httpSession = null;
+
+			// Proceed with chain
+			int contextWhenChainProceeded = SecurityContextHolder.getContext().hashCode();
+
+			try {
+				chain.doFilter(request, response);
+			}
+			catch (IOException ioe) {
+				throw ioe;
+			}
+			catch (ServletException se) {
+				throw se;
+			}
+			finally {
+				// do clean up, even if there was an exception
+				// Store context back to HttpSession
+				try {
+					httpSession = ((HttpServletRequest) request).getSession(false);
+				}
+				catch (IllegalStateException ignored) {
+				}
+
+				if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
+					if (logger.isDebugEnabled()) {
+						logger.debug("HttpSession is now null, but was not null at start of request; "
+								+ "session was invalidated, so do not create a new session");
+					}
+				}
+
+				// Generate a HttpSession only if we need to
+				if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) {
+					if (!allowSessionCreation) {
+						if (logger.isDebugEnabled()) {
+							logger
+									.debug("The HttpSession is currently null, and the "
+											+ "HttpSessionContextIntegrationFilter is prohibited from creating an HttpSession "
+											+ "(because the allowSessionCreation property is false) - SecurityContext thus not "
+											+ "stored for next request");
+						}
+					}
+					else if (!contextObject.equals(SecurityContextHolder.getContext())) {
+						if (logger.isDebugEnabled()) {
+							logger.debug("HttpSession being created as SecurityContextHolder contents are non-default");
+						}
+
+						try {
+							httpSession = ((HttpServletRequest) request).getSession(true);
+						}
+						catch (IllegalStateException ignored) {
+						}
+					}
+					else {
+						if (logger.isDebugEnabled()) {
+							logger
+									.debug("HttpSession is null, but SecurityContextHolder has not changed from default: ' "
+											+ SecurityContextHolder.getContext()
+											+ "'; not creating HttpSession or storing SecurityContextHolder contents");
+						}
+					}
+				}
+
+				// If HttpSession exists, store current
+				// SecurityContextHolder contents but only if
+				// SecurityContext has
+				// actually changed (see JIRA SEC-37)
+				if ((httpSession != null)
+						&& (SecurityContextHolder.getContext().hashCode() != contextWhenChainProceeded)) {
+					httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
+
+					if (logger.isDebugEnabled()) {
+						logger.debug("SecurityContext stored to HttpSession: '" + SecurityContextHolder.getContext()
+								+ "'");
+					}
+				}
+
+				// Remove SecurityContextHolder contents
+				SecurityContextHolder.clearContext();
+
+				if (logger.isDebugEnabled()) {
+					logger.debug("SecurityContextHolder set to new context, as request processing completed");
+				}
+			}
+		}
+	}
+
+	public SecurityContext generateNewContext() throws ServletException {
+		try {
+			return (SecurityContext) this.context.newInstance();
+		}
+		catch (InstantiationException ie) {
+			throw new ServletException(ie);
+		}
+		catch (IllegalAccessException iae) {
+			throw new ServletException(iae);
+		}
+	}
+
+	public Class getContext() {
+		return context;
+	}
+
+	/**
+	 * Does nothing. We use IoC container lifecycle services instead.
+	 * 
+	 * @param filterConfig ignored
+	 * 
+	 * @throws ServletException ignored
+	 */
+	public void init(FilterConfig filterConfig) throws ServletException {
+	}
+
+	public boolean isAllowSessionCreation() {
+		return allowSessionCreation;
+	}
+
+	public boolean isForceEagerSessionCreation() {
+		return forceEagerSessionCreation;
+	}
+
+	public void setAllowSessionCreation(boolean allowSessionCreation) {
+		this.allowSessionCreation = allowSessionCreation;
+	}
+
+	public void setContext(Class secureContext) {
+		this.context = secureContext;
+	}
+
+	public void setForceEagerSessionCreation(boolean forceEagerSessionCreation) {
+		this.forceEagerSessionCreation = forceEagerSessionCreation;
+	}
 }