Răsfoiți Sursa

SEC-398: Lazy update of 'filterApplied' to true

Vishal Puri 18 ani în urmă
părinte
comite
bc30b903f8

+ 92 - 73
core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java

@@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.util.Assert;
 import org.springframework.util.Assert;
 import org.springframework.util.ReflectionUtils;
 import org.springframework.util.ReflectionUtils;
+import org.springframework.web.util.WebUtils;
 
 
 /**
 /**
  * Populates the {@link SecurityContextHolder} with information obtained from
  * Populates the {@link SecurityContextHolder} with information obtained from
@@ -94,13 +95,15 @@ import org.springframework.util.ReflectionUtils;
  * @author Ben Alex
  * @author Ben Alex
  * @author Patrick Burleson
  * @author Patrick Burleson
  * @version $Id: HttpSessionContextIntegrationFilter.java 1784 2007-02-24
  * @version $Id: HttpSessionContextIntegrationFilter.java 1784 2007-02-24
- * 21:00:24Z luke_t $
+ *          21:00:24Z luke_t $
  */
  */
-public class HttpSessionContextIntegrationFilter implements InitializingBean, Filter {
+public class HttpSessionContextIntegrationFilter implements InitializingBean,
+		Filter {
 	// ~ Static fields/initializers
 	// ~ Static fields/initializers
 	// =====================================================================================
 	// =====================================================================================
 
 
-	protected static final Log logger = LogFactory.getLog(HttpSessionContextIntegrationFilter.class);
+	protected static final Log logger = LogFactory
+			.getLog(HttpSessionContextIntegrationFilter.class);
 
 
 	static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";
 	static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";
 
 
@@ -172,13 +175,16 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
 	// ========================================================================================================
 	// ========================================================================================================
 
 
 	public void afterPropertiesSet() throws Exception {
 	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 ((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)) {
+		if ((forceEagerSessionCreation == true)
+				&& (allowSessionCreation == false)) {
 			throw new IllegalArgumentException(
 			throw new IllegalArgumentException(
 					"If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
 					"If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
 		}
 		}
@@ -190,59 +196,60 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
 	public void destroy() {
 	public void destroy() {
 	}
 	}
 
 
-	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
-			ServletException {
+	public void doFilter(ServletRequest request, ServletResponse response,
+			FilterChain chain) throws IOException, ServletException {
 		boolean filterApplied = false;
 		boolean filterApplied = false;
 		if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {
 		if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {
 			// ensure that filter is only applied once per request
 			// ensure that filter is only applied once per request
+			System.out.println("Filter already applied so moving on");
 			chain.doFilter(request, response);
 			chain.doFilter(request, response);
-		}
-		else {
-			if (request != null) {
-				filterApplied = true;
-				request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
-			}
-
+		} else {
 			HttpSession httpSession = null;
 			HttpSession httpSession = null;
 			boolean httpSessionExistedAtStartOfRequest = false;
 			boolean httpSessionExistedAtStartOfRequest = false;
 
 
 			try {
 			try {
-				httpSession = ((HttpServletRequest) request).getSession(forceEagerSessionCreation);
-			}
-			catch (IllegalStateException ignored) {
+				httpSession = ((HttpServletRequest) request)
+						.getSession(forceEagerSessionCreation);
+			} catch (IllegalStateException ignored) {
 			}
 			}
 
 
 			if (httpSession != null) {
 			if (httpSession != null) {
 				httpSessionExistedAtStartOfRequest = true;
 				httpSessionExistedAtStartOfRequest = true;
 
 
-				Object contextFromSessionObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);
+				Object contextFromSessionObject = httpSession
+						.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);
 
 
 				if (contextFromSessionObject != null) {
 				if (contextFromSessionObject != null) {
 					// Clone if required (see SEC-356)
 					// Clone if required (see SEC-356)
 					if (cloneFromHttpSession) {
 					if (cloneFromHttpSession) {
-						Assert.isInstanceOf(Cloneable.class, contextFromSessionObject,
-								"Context must implement Clonable and provide a Object.clone() method");
+						Assert
+								.isInstanceOf(Cloneable.class,
+										contextFromSessionObject,
+										"Context must implement Clonable and provide a Object.clone() method");
 						try {
 						try {
-							Method m = contextFromSessionObject.getClass().getMethod("clone", new Class[] {});
+							Method m = contextFromSessionObject.getClass()
+									.getMethod("clone", new Class[] {});
 							if (!m.isAccessible()) {
 							if (!m.isAccessible()) {
 								m.setAccessible(true);
 								m.setAccessible(true);
 							}
 							}
-							contextFromSessionObject = m.invoke(contextFromSessionObject, new Object[] {});
-						}
-						catch (Exception ex) {
+							contextFromSessionObject = m.invoke(
+									contextFromSessionObject, new Object[] {});
+						} catch (Exception ex) {
 							ReflectionUtils.handleReflectionException(ex);
 							ReflectionUtils.handleReflectionException(ex);
 						}
 						}
 					}
 					}
 
 
 					if (contextFromSessionObject instanceof SecurityContext) {
 					if (contextFromSessionObject instanceof SecurityContext) {
 						if (logger.isDebugEnabled()) {
 						if (logger.isDebugEnabled()) {
-							logger.debug("Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and "
-									+ "set to SecurityContextHolder: '" + contextFromSessionObject + "'");
+							logger
+									.debug("Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and "
+											+ "set to SecurityContextHolder: '"
+											+ contextFromSessionObject + "'");
 						}
 						}
 
 
-						SecurityContextHolder.setContext((SecurityContext) contextFromSessionObject);
-					}
-					else {
+						SecurityContextHolder
+								.setContext((SecurityContext) contextFromSessionObject);
+					} else {
 						if (logger.isWarnEnabled()) {
 						if (logger.isWarnEnabled()) {
 							logger
 							logger
 									.warn("ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '"
 									.warn("ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '"
@@ -255,60 +262,66 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
 
 
 						SecurityContextHolder.setContext(generateNewContext());
 						SecurityContextHolder.setContext(generateNewContext());
 					}
 					}
-				}
-				else {
+				} else {
 					if (logger.isDebugEnabled()) {
 					if (logger.isDebugEnabled()) {
-						logger.debug("HttpSession returned null object for ACEGI_SECURITY_CONTEXT - new "
-								+ "SecurityContext instance associated with SecurityContextHolder");
+						logger
+								.debug("HttpSession returned null object for ACEGI_SECURITY_CONTEXT - new "
+										+ "SecurityContext instance associated with SecurityContextHolder");
 					}
 					}
 
 
 					SecurityContextHolder.setContext(generateNewContext());
 					SecurityContextHolder.setContext(generateNewContext());
 				}
 				}
-			}
-			else {
+
+			} else {
 				if (logger.isDebugEnabled()) {
 				if (logger.isDebugEnabled()) {
-					logger.debug("No HttpSession currently exists - new SecurityContext instance "
-							+ "associated with SecurityContextHolder");
+					logger
+							.debug("No HttpSession currently exists - new SecurityContext instance "
+									+ "associated with SecurityContextHolder");
 				}
 				}
 
 
 				SecurityContextHolder.setContext(generateNewContext());
 				SecurityContextHolder.setContext(generateNewContext());
 			}
 			}
 
 
+			// end synch
+
 			// Make the HttpSession null, as we want to ensure we don't keep
 			// Make the HttpSession null, as we want to ensure we don't keep
 			// a reference to the HttpSession laying around in case the
 			// a reference to the HttpSession laying around in case the
 			// chain.doFilter() invalidates it.
 			// chain.doFilter() invalidates it.
 			httpSession = null;
 			httpSession = null;
 
 
 			// Proceed with chain
 			// Proceed with chain
-			int contextWhenChainProceeded = SecurityContextHolder.getContext().hashCode();
+			int contextWhenChainProceeded = SecurityContextHolder.getContext()
+					.hashCode();
 
 
 			try {
 			try {
+				filterApplied = true;
+				request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
 				chain.doFilter(request, response);
 				chain.doFilter(request, response);
-			}
-			catch (IOException ioe) {
+			} catch (IOException ioe) {
 				throw ioe;
 				throw ioe;
-			}
-			catch (ServletException se) {
+			} catch (ServletException se) {
+
 				throw se;
 				throw se;
-			}
-			finally {
+			} finally {
 				// do clean up, even if there was an exception
 				// do clean up, even if there was an exception
 				// Store context back to HttpSession
 				// Store context back to HttpSession
 				try {
 				try {
-					httpSession = ((HttpServletRequest) request).getSession(false);
-				}
-				catch (IllegalStateException ignored) {
+					httpSession = ((HttpServletRequest) request)
+							.getSession(false);
+				} catch (IllegalStateException ignored) {
 				}
 				}
 
 
 				if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
 				if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
 					if (logger.isDebugEnabled()) {
 					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");
+						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
 				// Generate a HttpSession only if we need to
-				if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) {
+				if ((httpSession == null)
+						&& !httpSessionExistedAtStartOfRequest) {
 					if (!allowSessionCreation) {
 					if (!allowSessionCreation) {
 						if (logger.isDebugEnabled()) {
 						if (logger.isDebugEnabled()) {
 							logger
 							logger
@@ -317,23 +330,24 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
 											+ "(because the allowSessionCreation property is false) - SecurityContext thus not "
 											+ "(because the allowSessionCreation property is false) - SecurityContext thus not "
 											+ "stored for next request");
 											+ "stored for next request");
 						}
 						}
-					}
-					else if (!contextObject.equals(SecurityContextHolder.getContext())) {
+					} else if (!contextObject.equals(SecurityContextHolder
+							.getContext())) {
 						if (logger.isDebugEnabled()) {
 						if (logger.isDebugEnabled()) {
-							logger.debug("HttpSession being created as SecurityContextHolder contents are non-default");
+							logger
+									.debug("HttpSession being created as SecurityContextHolder contents are non-default");
 						}
 						}
 
 
 						try {
 						try {
-							httpSession = ((HttpServletRequest) request).getSession(true);
-						}
-						catch (IllegalStateException ignored) {
+							httpSession = ((HttpServletRequest) request)
+									.getSession(true);
+						} catch (IllegalStateException ignored) {
 						}
 						}
-					}
-					else {
+					} else {
 						if (logger.isDebugEnabled()) {
 						if (logger.isDebugEnabled()) {
 							logger
 							logger
 									.debug("HttpSession is null, but SecurityContextHolder has not changed from default: ' "
 									.debug("HttpSession is null, but SecurityContextHolder has not changed from default: ' "
-											+ SecurityContextHolder.getContext()
+											+ SecurityContextHolder
+													.getContext()
 											+ "'; not creating HttpSession or storing SecurityContextHolder contents");
 											+ "'; not creating HttpSession or storing SecurityContextHolder contents");
 						}
 						}
 					}
 					}
@@ -345,36 +359,39 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
 				// actually changed (see JIRA SEC-37)
 				// actually changed (see JIRA SEC-37)
 				if ((httpSession != null)
 				if ((httpSession != null)
 						&& (SecurityContextHolder.getContext().hashCode() != contextWhenChainProceeded)) {
 						&& (SecurityContextHolder.getContext().hashCode() != contextWhenChainProceeded)) {
-					httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
+					httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY,
+							SecurityContextHolder.getContext());
 
 
 					if (logger.isDebugEnabled()) {
 					if (logger.isDebugEnabled()) {
-						logger.debug("SecurityContext stored to HttpSession: '" + SecurityContextHolder.getContext()
-								+ "'");
+						logger.debug("SecurityContext stored to HttpSession: '"
+								+ SecurityContextHolder.getContext() + "'");
 					}
 					}
 				}
 				}
 
 
 				if (filterApplied) {
 				if (filterApplied) {
 					request.removeAttribute(FILTER_APPLIED);
 					request.removeAttribute(FILTER_APPLIED);
 				}
 				}
-				
+
 				// Remove SecurityContextHolder contents
 				// Remove SecurityContextHolder contents
 				SecurityContextHolder.clearContext();
 				SecurityContextHolder.clearContext();
 
 
 				if (logger.isDebugEnabled()) {
 				if (logger.isDebugEnabled()) {
-					logger.debug("SecurityContextHolder set to new context, as request processing completed");
+					logger
+							.debug("SecurityContextHolder set to new context, as request processing completed");
 				}
 				}
+
 			}
 			}
+
 		}
 		}
+
 	}
 	}
 
 
 	public SecurityContext generateNewContext() throws ServletException {
 	public SecurityContext generateNewContext() throws ServletException {
 		try {
 		try {
 			return (SecurityContext) this.context.newInstance();
 			return (SecurityContext) this.context.newInstance();
-		}
-		catch (InstantiationException ie) {
+		} catch (InstantiationException ie) {
 			throw new ServletException(ie);
 			throw new ServletException(ie);
-		}
-		catch (IllegalAccessException iae) {
+		} catch (IllegalAccessException iae) {
 			throw new ServletException(iae);
 			throw new ServletException(iae);
 		}
 		}
 	}
 	}
@@ -386,9 +403,11 @@ public class HttpSessionContextIntegrationFilter implements InitializingBean, Fi
 	/**
 	/**
 	 * Does nothing. We use IoC container lifecycle services instead.
 	 * Does nothing. We use IoC container lifecycle services instead.
 	 * 
 	 * 
-	 * @param filterConfig ignored
+	 * @param filterConfig
+	 *            ignored
 	 * 
 	 * 
-	 * @throws ServletException ignored
+	 * @throws ServletException
+	 *             ignored
 	 */
 	 */
 	public void init(FilterConfig filterConfig) throws ServletException {
 	public void init(FilterConfig filterConfig) throws ServletException {
 	}
 	}

+ 379 - 262
core/src/test/java/org/acegisecurity/context/HttpSessionContextIntegrationFilterTests.java

@@ -23,6 +23,7 @@ import org.acegisecurity.GrantedAuthorityImpl;
 import org.acegisecurity.MockFilterConfig;
 import org.acegisecurity.MockFilterConfig;
 
 
 import org.acegisecurity.adapters.PrincipalAcegiUserToken;
 import org.acegisecurity.adapters.PrincipalAcegiUserToken;
+import org.jmock.Mock;
 
 
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.mock.web.MockHttpServletResponse;
@@ -36,271 +37,387 @@ import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.ServletResponse;
 
 
-
 /**
 /**
  * Tests {@link HttpSessionContextIntegrationFilter}.
  * Tests {@link HttpSessionContextIntegrationFilter}.
- *
+ * 
  * @author Ben Alex
  * @author Ben Alex
- * @version $Id$
+ * @version $Id: HttpSessionContextIntegrationFilterTests.java 1858 2007-05-24
+ *          02:04:47Z benalex $
  */
  */
 public class HttpSessionContextIntegrationFilterTests extends TestCase {
 public class HttpSessionContextIntegrationFilterTests extends TestCase {
-    //~ Constructors ===================================================================================================
-
-    public HttpSessionContextIntegrationFilterTests() {
-        super();
-    }
-
-    public HttpSessionContextIntegrationFilterTests(String arg0) {
-        super(arg0);
-    }
-
-    //~ Methods ========================================================================================================
-
-    private void executeFilterInContainerSimulator(FilterConfig filterConfig, Filter filter, ServletRequest request,
-        ServletResponse response, FilterChain filterChain)
-        throws ServletException, IOException {
-        filter.init(filterConfig);
-        filter.doFilter(request, response, filterChain);
-        filter.destroy();
-    }
-
-    public static void main(String[] args) {
-        junit.textui.TestRunner.run(HttpSessionContextIntegrationFilterTests.class);
-    }
-
-    public void testDetectsIncompatibleSessionProperties()
-        throws Exception {
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-
-        try {
-            filter.setAllowSessionCreation(false);
-            filter.setForceEagerSessionCreation(true);
-            filter.afterPropertiesSet();
-            fail("Shown have thrown IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {
-            assertTrue(true);
-        }
-
-        filter.setAllowSessionCreation(true);
-        filter.afterPropertiesSet();
-        assertTrue(true);
-    }
-
-    public void testDetectsMissingOrInvalidContext() throws Exception {
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-
-        try {
-            filter.setContext(null);
-            filter.afterPropertiesSet();
-            fail("Shown have thrown IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {
-            assertTrue(true);
-        }
-
-        try {
-            filter.setContext(Integer.class);
-            assertEquals(Integer.class, filter.getContext());
-            filter.afterPropertiesSet();
-            fail("Shown have thrown IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {
-            assertTrue(true);
-        }
-    }
-
-    public void testExceptionWithinFilterChainStillClearsSecurityContextHolder()
-        throws Exception {
-        // Build an Authentication object we simulate came from HttpSession
-        PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key", "someone", "password",
-                new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}, null);
-
-        // Build a Context to store in HttpSession (simulating prior request)
-        SecurityContext sc = new SecurityContextImpl();
-        sc.setAuthentication(sessionPrincipal);
-
-        // Build a mock request
-        MockHttpServletRequest request = new MockHttpServletRequest();
-        request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, sc);
-
-        MockHttpServletResponse response = new MockHttpServletResponse();
-        FilterChain chain = new MockFilterChain(sessionPrincipal, null, new IOException());
-
-        // Prepare filter
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-        filter.setContext(SecurityContextImpl.class);
-        filter.afterPropertiesSet();
-
-        // Execute filter
-        try {
-            executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
-            fail("We should have received the IOException thrown inside the filter chain here");
-        } catch (IOException ioe) {
-            assertTrue(true);
-        }
-
-        // Check the SecurityContextHolder is null, even though an exception was thrown during chain
-        assertEquals(new SecurityContextImpl(), SecurityContextHolder.getContext());
-        assertNull("Should have cleared FILTER_APPLIED", request.getAttribute(HttpSessionContextIntegrationFilter.FILTER_APPLIED));
-    }
-
-    public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
-        throws Exception {
-        // Build an Authentication object we simulate came from HttpSession
-        PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken("key", "someone", "password",
-                new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_ROLE")}, null);
-
-        // Build an Authentication object we simulate our Authentication changed it to
-        PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key", "someone", "password",
-                new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")}, null);
-
-        // Build a Context to store in HttpSession (simulating prior request)
-        SecurityContext sc = new SecurityContextImpl();
-        sc.setAuthentication(sessionPrincipal);
-
-        // Build a mock request
-        MockHttpServletRequest request = new MockHttpServletRequest();
-        request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, sc);
-
-        MockHttpServletResponse response = new MockHttpServletResponse();
-        FilterChain chain = new MockFilterChain(sessionPrincipal, updatedPrincipal, null);
-
-        // Prepare filter
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-        filter.setContext(SecurityContextImpl.class);
-        filter.afterPropertiesSet();
-
-        // Execute filter
-        executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
-
-        // Obtain new/update Authentication from HttpSession
-        SecurityContext context = (SecurityContext) request.getSession()
-                                                           .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
-        assertEquals(updatedPrincipal, ((SecurityContext) context).getAuthentication());
-    }
-
-    public void testHttpSessionCreatedWhenContextHolderChanges()
-        throws Exception {
-        // Build an Authentication object we simulate our Authentication changed it to
-        PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key", "someone", "password",
-                new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")}, null);
-
-        // Build a mock request
-        MockHttpServletRequest request = new MockHttpServletRequest();
-        MockHttpServletResponse response = new MockHttpServletResponse();
-        FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
-
-        // Prepare filter
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-        filter.setContext(SecurityContextImpl.class);
-        // don't call afterPropertiesSet to test case when not instantiated by Spring 
-        //filter.afterPropertiesSet();
-
-        // Execute filter
-        executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
-
-        // Obtain new/updated Authentication from HttpSession
-        SecurityContext context = (SecurityContext) request.getSession(false)
-                                                           .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
-        assertEquals(updatedPrincipal, ((SecurityContext) context).getAuthentication());
-    }
-
-    public void testHttpSessionEagerlyCreatedWhenDirected()
-        throws Exception {
-        // Build a mock request
-        MockHttpServletRequest request = new MockHttpServletRequest(null, null);
-        MockHttpServletResponse response = new MockHttpServletResponse();
-        FilterChain chain = new MockFilterChain(null, null, null);
-
-        // Prepare filter
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-        filter.setContext(SecurityContextImpl.class);
-        filter.setForceEagerSessionCreation(true); // non-default
-        filter.afterPropertiesSet();
-
-        // Execute filter
-        executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
-
-        // Check the session is not null
-        assertNotNull(request.getSession(false));
-    }
-
-    public void testHttpSessionNotCreatedUnlessContextHolderChanges()
-        throws Exception {
-        // Build a mock request
-        MockHttpServletRequest request = new MockHttpServletRequest(null, null);
-        MockHttpServletResponse response = new MockHttpServletResponse();
-        FilterChain chain = new MockFilterChain(null, null, null);
-
-        // Prepare filter
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-        filter.setContext(SecurityContextImpl.class);
-        filter.afterPropertiesSet();
-
-        // Execute filter
-        executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
-
-        // Check the session is null
-        assertNull(request.getSession(false));
-    }
-
-    public void testHttpSessionWithNonContextInWellKnownLocationIsOverwritten()
-        throws Exception {
-        // Build an Authentication object we simulate our Authentication changed it to
-        PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken("key", "someone", "password",
-                new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")}, null);
-
-        // Build a mock request
-        MockHttpServletRequest request = new MockHttpServletRequest();
-        request.getSession()
-               .setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, "NOT_A_CONTEXT_OBJECT");
-
-        MockHttpServletResponse response = new MockHttpServletResponse();
-        FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
-
-        // Prepare filter
-        HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
-        filter.setContext(SecurityContextImpl.class);
-        filter.afterPropertiesSet();
-
-        // Execute filter
-        executeFilterInContainerSimulator(new MockFilterConfig(), filter, request, response, chain);
-
-        // Obtain new/update Authentication from HttpSession
-        SecurityContext context = (SecurityContext) request.getSession()
-                                                           .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
-        assertEquals(updatedPrincipal, ((SecurityContext) context).getAuthentication());
-    }
-
-    //~ Inner Classes ==================================================================================================
-
-    private class MockFilterChain extends TestCase implements FilterChain {
-        private Authentication changeContextHolder;
-        private Authentication expectedOnContextHolder;
-        private IOException toThrowDuringChain;
-
-        public MockFilterChain(Authentication expectedOnContextHolder, Authentication changeContextHolder,
-            IOException toThrowDuringChain) {
-            this.expectedOnContextHolder = expectedOnContextHolder;
-            this.changeContextHolder = changeContextHolder;
-            this.toThrowDuringChain = toThrowDuringChain;
-        }
-
-        private MockFilterChain() {}
-
-        public void doFilter(ServletRequest arg0, ServletResponse arg1)
-            throws IOException, ServletException {
-            if (expectedOnContextHolder != null) {
-                assertEquals(expectedOnContextHolder, SecurityContextHolder.getContext().getAuthentication());
-            }
-
-            if (changeContextHolder != null) {
-                SecurityContext sc = SecurityContextHolder.getContext();
-                sc.setAuthentication(changeContextHolder);
-                SecurityContextHolder.setContext(sc);
-            }
-
-            if (toThrowDuringChain != null) {
-                throw toThrowDuringChain;
-            }
-        }
-    }
+	// ~ Constructors
+	// ===================================================================================================
+
+	public HttpSessionContextIntegrationFilterTests() {
+		super();
+	}
+
+	public HttpSessionContextIntegrationFilterTests(String arg0) {
+		super(arg0);
+	}
+
+	// ~ Methods
+	// ========================================================================================================
+
+	private static void executeFilterInContainerSimulator(
+			FilterConfig filterConfig, Filter filter, ServletRequest request,
+			ServletResponse response, FilterChain filterChain)
+			throws ServletException, IOException {
+		filter.init(filterConfig);
+		filter.doFilter(request, response, filterChain);
+		filter.destroy();
+	}
+
+	public static void main(String[] args) {
+		junit.textui.TestRunner
+				.run(HttpSessionContextIntegrationFilterTests.class);
+	}
+
+	public void testDetectsIncompatibleSessionProperties() throws Exception {
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+
+		try {
+			filter.setAllowSessionCreation(false);
+			filter.setForceEagerSessionCreation(true);
+			filter.afterPropertiesSet();
+			fail("Shown have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException expected) {
+			assertTrue(true);
+		}
+
+		filter.setAllowSessionCreation(true);
+		filter.afterPropertiesSet();
+		assertTrue(true);
+	}
+
+	public void testDetectsMissingOrInvalidContext() throws Exception {
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+
+		try {
+			filter.setContext(null);
+			filter.afterPropertiesSet();
+			fail("Shown have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException expected) {
+			assertTrue(true);
+		}
+
+		try {
+			filter.setContext(Integer.class);
+			assertEquals(Integer.class, filter.getContext());
+			filter.afterPropertiesSet();
+			fail("Shown have thrown IllegalArgumentException");
+		} catch (IllegalArgumentException expected) {
+			assertTrue(true);
+		}
+	}
+
+	public void testExceptionWithinFilterChainStillClearsSecurityContextHolder()
+			throws Exception {
+		// Build an Authentication object we simulate came from HttpSession
+		PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken(
+				"key",
+				"someone",
+				"password",
+				new GrantedAuthority[] { new GrantedAuthorityImpl("SOME_ROLE") },
+				null);
+
+		// Build a Context to store in HttpSession (simulating prior request)
+		SecurityContext sc = new SecurityContextImpl();
+		sc.setAuthentication(sessionPrincipal);
+
+		// Build a mock request
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.getSession().setAttribute(
+				HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
+				sc);
+
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		FilterChain chain = new MockFilterChain(sessionPrincipal, null,
+				new IOException());
+
+		// Prepare filter
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+		filter.setContext(SecurityContextImpl.class);
+		filter.afterPropertiesSet();
+
+		// Execute filter
+		try {
+			executeFilterInContainerSimulator(new MockFilterConfig(), filter,
+					request, response, chain);
+			fail("We should have received the IOException thrown inside the filter chain here");
+		} catch (IOException ioe) {
+			assertTrue(true);
+		}
+
+		// Check the SecurityContextHolder is null, even though an exception was
+		// thrown during chain
+		assertEquals(new SecurityContextImpl(), SecurityContextHolder
+				.getContext());
+		assertNull(
+				"Should have cleared FILTER_APPLIED",
+				request
+						.getAttribute(HttpSessionContextIntegrationFilter.FILTER_APPLIED));
+	}
+
+	public void testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
+			throws Exception {
+		// Build an Authentication object we simulate came from HttpSession
+		PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken(
+				"key",
+				"someone",
+				"password",
+				new GrantedAuthority[] { new GrantedAuthorityImpl("SOME_ROLE") },
+				null);
+
+		// Build an Authentication object we simulate our Authentication changed
+		// it to
+		PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken(
+				"key", "someone", "password",
+				new GrantedAuthority[] { new GrantedAuthorityImpl(
+						"SOME_DIFFERENT_ROLE") }, null);
+
+		// Build a Context to store in HttpSession (simulating prior request)
+		SecurityContext sc = new SecurityContextImpl();
+		sc.setAuthentication(sessionPrincipal);
+
+		// Build a mock request
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.getSession().setAttribute(
+				HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
+				sc);
+
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		FilterChain chain = new MockFilterChain(sessionPrincipal,
+				updatedPrincipal, null);
+
+		// Prepare filter
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+		filter.setContext(SecurityContextImpl.class);
+		filter.afterPropertiesSet();
+
+		// Execute filter
+		executeFilterInContainerSimulator(new MockFilterConfig(), filter,
+				request, response, chain);
+
+		// Obtain new/update Authentication from HttpSession
+		SecurityContext context = (SecurityContext) request
+				.getSession()
+				.getAttribute(
+						HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
+		assertEquals(updatedPrincipal, ((SecurityContext) context)
+				.getAuthentication());
+	}
+
+	public void testHttpSessionCreatedWhenContextHolderChanges()
+			throws Exception {
+		// Build an Authentication object we simulate our Authentication changed
+		// it to
+		PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken(
+				"key", "someone", "password",
+				new GrantedAuthority[] { new GrantedAuthorityImpl(
+						"SOME_DIFFERENT_ROLE") }, null);
+
+		// Build a mock request
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
+
+		// Prepare filter
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+		filter.setContext(SecurityContextImpl.class);
+		// don't call afterPropertiesSet to test case when not instantiated by
+		// Spring
+		// filter.afterPropertiesSet();
+
+		// Execute filter
+		executeFilterInContainerSimulator(new MockFilterConfig(), filter,
+				request, response, chain);
+
+		// Obtain new/updated Authentication from HttpSession
+		SecurityContext context = (SecurityContext) request
+				.getSession(false)
+				.getAttribute(
+						HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
+		assertEquals(updatedPrincipal, ((SecurityContext) context)
+				.getAuthentication());
+	}
+
+	public void testHttpSessionEagerlyCreatedWhenDirected() throws Exception {
+		// Build a mock request
+		MockHttpServletRequest request = new MockHttpServletRequest(null, null);
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		FilterChain chain = new MockFilterChain(null, null, null);
+
+		// Prepare filter
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+		filter.setContext(SecurityContextImpl.class);
+		filter.setForceEagerSessionCreation(true); // non-default
+		filter.afterPropertiesSet();
+
+		// Execute filter
+		executeFilterInContainerSimulator(new MockFilterConfig(), filter,
+				request, response, chain);
+
+		// Check the session is not null
+		assertNotNull(request.getSession(false));
+	}
+
+	public void testHttpSessionNotCreatedUnlessContextHolderChanges()
+			throws Exception {
+		// Build a mock request
+		MockHttpServletRequest request = new MockHttpServletRequest(null, null);
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		FilterChain chain = new MockFilterChain(null, null, null);
+
+		// Prepare filter
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+		filter.setContext(SecurityContextImpl.class);
+		filter.afterPropertiesSet();
+
+		// Execute filter
+		executeFilterInContainerSimulator(new MockFilterConfig(), filter,
+				request, response, chain);
+
+		// Check the session is null
+		assertNull(request.getSession(false));
+	}
+
+	public void testHttpSessionWithNonContextInWellKnownLocationIsOverwritten()
+			throws Exception {
+		// Build an Authentication object we simulate our Authentication changed
+		// it to
+		PrincipalAcegiUserToken updatedPrincipal = new PrincipalAcegiUserToken(
+				"key", "someone", "password",
+				new GrantedAuthority[] { new GrantedAuthorityImpl(
+						"SOME_DIFFERENT_ROLE") }, null);
+
+		// Build a mock request
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.getSession().setAttribute(
+				HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
+				"NOT_A_CONTEXT_OBJECT");
+
+		MockHttpServletResponse response = new MockHttpServletResponse();
+		FilterChain chain = new MockFilterChain(null, updatedPrincipal, null);
+
+		// Prepare filter
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+		filter.setContext(SecurityContextImpl.class);
+		filter.afterPropertiesSet();
+
+		// Execute filter
+		executeFilterInContainerSimulator(new MockFilterConfig(), filter,
+				request, response, chain);
+
+		// Obtain new/update Authentication from HttpSession
+		SecurityContext context = (SecurityContext) request
+				.getSession()
+				.getAttribute(
+						HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
+		assertEquals(updatedPrincipal, ((SecurityContext) context)
+				.getAuthentication());
+	}
+
+	public void testConcurrentThreadsLazilyChangeFilterAppliedValueToTrue()
+			throws Exception {
+		PrincipalAcegiUserToken sessionPrincipal = new PrincipalAcegiUserToken(
+				"key",
+				"someone",
+				"password",
+				new GrantedAuthority[] { new GrantedAuthorityImpl("SOME_ROLE") },
+				null);
+
+		// Build a Context to store in HttpSession (simulating prior request)
+		SecurityContext sc = new SecurityContextImpl();
+		sc.setAuthentication(sessionPrincipal);
+
+		MockHttpServletRequest request = new MockHttpServletRequest();
+		request.getSession().setAttribute(
+				HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
+				sc);
+		MockHttpServletResponse response = new MockHttpServletResponse();
+
+		// Prepare filter
+		HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+		filter.setContext(SecurityContextImpl.class);
+		filter.afterPropertiesSet();
+
+		for (int i = 0; i < 3; i++) {
+			ThreadRunner runner = new ThreadRunner(request, response, filter,
+					new MockFilterChain(sessionPrincipal, null, null));
+			runner.start();
+		}
+
+	}
+
+	// ~ Inner Classes
+	// ==================================================================================================
+
+	private class MockFilterChain extends TestCase implements FilterChain {
+		private Authentication changeContextHolder;
+		private Authentication expectedOnContextHolder;
+		private IOException toThrowDuringChain;
+
+		public MockFilterChain(Authentication expectedOnContextHolder,
+				Authentication changeContextHolder,
+				IOException toThrowDuringChain) {
+			this.expectedOnContextHolder = expectedOnContextHolder;
+			this.changeContextHolder = changeContextHolder;
+			this.toThrowDuringChain = toThrowDuringChain;
+		}
+
+		private MockFilterChain() {
+		}
+
+		public void doFilter(ServletRequest arg0, ServletResponse arg1)
+				throws IOException, ServletException {
+
+			if (expectedOnContextHolder != null) {
+				assertEquals(expectedOnContextHolder, SecurityContextHolder
+						.getContext().getAuthentication());
+			}
+
+			if (changeContextHolder != null) {
+				SecurityContext sc = SecurityContextHolder.getContext();
+				sc.setAuthentication(changeContextHolder);
+				SecurityContextHolder.setContext(sc);
+			}
+
+			if (toThrowDuringChain != null) {
+				throw toThrowDuringChain;
+			}
+
+		}
+	}
+
+	private static class ThreadRunner extends Thread {
+		private MockHttpServletRequest request;
+		private MockHttpServletResponse response;
+		private HttpSessionContextIntegrationFilter filter;
+		private MockFilterChain chain;
+
+		public ThreadRunner(MockHttpServletRequest request,
+				MockHttpServletResponse response,
+				HttpSessionContextIntegrationFilter filter,
+				MockFilterChain chain) {
+			this.request = request;
+			this.response = response;
+			this.filter = filter;
+			this.chain = chain;
+		}
+
+		public void run() {
+			try {
+				// Execute filter
+				executeFilterInContainerSimulator(new MockFilterConfig(),
+						filter, request, response, chain);
+
+				// Check the session is not null
+				assertNotNull(request.getSession(false));
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+
+	}
 }
 }