Browse Source

Refactor SecurityContextHolder to return a SecurityContext instead of Authentication.

Ben Alex 20 years ago
parent
commit
e08e66dec6
56 changed files with 759 additions and 399 deletions
  1. 2 2
      adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java
  2. 12 10
      adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilterTests.java
  3. 2 2
      core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java
  4. 101 60
      core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java
  5. 25 16
      core/src/main/java/org/acegisecurity/context/SecurityContext.java
  6. 78 0
      core/src/main/java/org/acegisecurity/context/SecurityContextHolder.java
  7. 79 0
      core/src/main/java/org/acegisecurity/context/SecurityContextImpl.java
  8. 3 2
      core/src/main/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java
  9. 0 4
      core/src/main/java/org/acegisecurity/context/package.html
  10. 20 17
      core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocation.java
  11. 14 12
      core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java
  12. 2 2
      core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java
  13. 10 7
      core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilter.java
  14. 2 2
      core/src/main/java/org/acegisecurity/providers/jaas/SecureContextLoginModule.java
  15. 5 4
      core/src/main/java/org/acegisecurity/taglibs/authz/AclTag.java
  16. 4 3
      core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java
  17. 3 2
      core/src/main/java/org/acegisecurity/taglibs/authz/AuthorizeTag.java
  18. 6 5
      core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java
  19. 3 3
      core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java
  20. 3 3
      core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java
  21. 11 8
      core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java
  22. 5 5
      core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java
  23. 3 2
      core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapper.java
  24. 5 3
      core/src/test/java/org/acegisecurity/TargetObject.java
  25. 10 9
      core/src/test/java/org/acegisecurity/adapters/HttpRequestIntegrationFilterTests.java
  26. 54 14
      core/src/test/java/org/acegisecurity/context/HttpSessionContextIntegrationFilterTests.java
  27. 19 16
      core/src/test/java/org/acegisecurity/context/SecurityContextHolderTests.java
  28. 65 0
      core/src/test/java/org/acegisecurity/context/SecurityContextImplTests.java
  29. 4 4
      core/src/test/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java
  30. 6 5
      core/src/test/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationTests.java
  31. 5 5
      core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java
  32. 12 12
      core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java
  33. 5 5
      core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java
  34. 6 5
      core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java
  35. 5 4
      core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
  36. 9 6
      core/src/test/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilterTests.java
  37. 8 7
      core/src/test/java/org/acegisecurity/providers/jaas/SecureContextLoginModuleTest.java
  38. 17 17
      core/src/test/java/org/acegisecurity/taglibs/authz/AclTagTests.java
  39. 6 6
      core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java
  40. 4 3
      core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagAttributeTests.java
  41. 5 4
      core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagCustomGrantedAuthorityTests.java
  42. 4 3
      core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagExpressionLanguageTests.java
  43. 6 5
      core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagTests.java
  44. 18 14
      core/src/test/java/org/acegisecurity/ui/AbstractProcessingFilterTests.java
  45. 15 14
      core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java
  46. 21 20
      core/src/test/java/org/acegisecurity/ui/digestauth/DigestProcessingFilterTests.java
  47. 11 7
      core/src/test/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilterTests.java
  48. 10 8
      core/src/test/java/org/acegisecurity/ui/x509/X509ProcessingFilterTests.java
  49. 9 9
      core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapperTests.java
  50. 1 1
      doc/xdocs/changes.xml
  51. 9 9
      doc/xdocs/upgrade/upgrade-080-090.html
  52. 4 3
      samples/attributes/src/main/java/sample/attributes/Main.java
  53. 4 3
      samples/attributes/src/test/java/sample/attributes/BankTests.java
  54. 4 3
      samples/contacts/src/main/java/sample/contact/ClientApplication.java
  55. 3 2
      samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java
  56. 2 2
      samples/contacts/src/main/webapp/common/secure/debug.jsp

+ 2 - 2
adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilter.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.adapters.jboss;
 
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -74,7 +74,7 @@ public class JbossIntegrationFilter implements Filter {
         Object principal = extractFromContainer(request);
 
         if ((principal != null) && principal instanceof Authentication) {
-            SecurityContext.setAuthentication((Authentication) principal);
+            SecurityContextHolder.getContext().setAuthentication((Authentication) principal);
 
             if (logger.isDebugEnabled()) {
                 logger.debug(

+ 12 - 10
adapters/jboss/src/test/java/org/acegisecurity/adapters/jboss/JbossIntegrationFilterTests.java

@@ -20,7 +20,8 @@ import junit.framework.TestCase;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 
 import org.springframework.mock.web.MockHttpServletRequest;
 
@@ -79,8 +80,9 @@ public class JbossIntegrationFilterTests extends TestCase {
 
         filter.doFilter(request, null, chain);
 
-        assertEquals(principal, SecurityContext.getAuthentication());
-        SecurityContext.setAuthentication(null);
+        assertEquals(principal,
+            SecurityContextHolder.getContext().getAuthentication());
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     public void testReturnsNullIfContextReturnsSomethingOtherThanASubject()
@@ -92,7 +94,7 @@ public class JbossIntegrationFilterTests extends TestCase {
         MockFilterChain chain = new MockFilterChain();
 
         filter.doFilter(request, null, chain);
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testReturnsNullIfInitialContextHasNullPrincipal()
@@ -104,7 +106,7 @@ public class JbossIntegrationFilterTests extends TestCase {
         MockFilterChain chain = new MockFilterChain();
 
         filter.doFilter(request, null, chain);
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testReturnsNullIfInitialContextHasNullSubject()
@@ -116,7 +118,7 @@ public class JbossIntegrationFilterTests extends TestCase {
         MockFilterChain chain = new MockFilterChain();
 
         filter.doFilter(request, null, chain);
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testReturnsNullIfInitialContextIsNull()
@@ -127,7 +129,7 @@ public class JbossIntegrationFilterTests extends TestCase {
         MockFilterChain chain = new MockFilterChain();
 
         filter.doFilter(request, null, chain);
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testReturnsNullIfPrincipalNotAnAuthenticationImplementation()
@@ -143,7 +145,7 @@ public class JbossIntegrationFilterTests extends TestCase {
         MockFilterChain chain = new MockFilterChain();
 
         filter.doFilter(request, null, chain);
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testTestingObjectReturnsInitialContext()
@@ -154,12 +156,12 @@ public class JbossIntegrationFilterTests extends TestCase {
 
     protected void setUp() throws Exception {
         super.setUp();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     private void executeFilterInContainerSimulator(FilterConfig filterConfig,

+ 2 - 2
core/src/main/java/org/acegisecurity/adapters/HttpRequestIntegrationFilter.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.adapters;
 
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -75,7 +75,7 @@ public class HttpRequestIntegrationFilter implements Filter {
                 .getUserPrincipal();
 
             if ((principal != null) && principal instanceof Authentication) {
-                SecurityContext.setAuthentication((Authentication) principal);
+                SecurityContextHolder.getContext().setAuthentication((Authentication) principal);
 
                 if (logger.isDebugEnabled()) {
                     logger.debug(

+ 101 - 60
core/src/main/java/org/acegisecurity/context/HttpSessionContextIntegrationFilter.java

@@ -15,11 +15,11 @@
 
 package net.sf.acegisecurity.context;
 
-import net.sf.acegisecurity.Authentication;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.springframework.beans.factory.InitializingBean;
+
 import java.io.IOException;
 
 import javax.servlet.Filter;
@@ -34,27 +34,38 @@ import javax.servlet.http.HttpSession;
 
 /**
  * <p>
- * Populates the <code>SecurityContext</code> with information obtained from
- * the <code>HttpSession</code>.
+ * Populates the <code>SecurityContextHolder</code> with information obtained
+ * from the <code>HttpSession</code>.
  * </p>
  * 
  * <p>
  * The <code>HttpSession</code> will be queried to retrieve the
- * <code>Authentication</code> that should be stored against the
- * <code>SecurityContext</code> for the duration of the web request. At the
- * end of the web request, any updates made to the
- * <code>SecurityContext</code> will be persisted back to 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
+ * net.sf.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
- * <code>SecurityContext</code> are not <code>null</code>. This avoids
- * needless <code>HttpSession</code> creation, but automates the storage of
- * changes made to the <code>SecurityContext</code>.
+ * <code>ContextHolder</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>ContextHolder</code>.
  * </p>
  * 
  * <P>
@@ -68,30 +79,35 @@ import javax.servlet.http.HttpSession;
  * 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>SecurityContext</code> are
- * designed to have no persistence of the <code>Authentication</code> between
- * web requests.
+ * memory and ensure all classes using the <code>ContextHolder</code> are
+ * designed to have no persistence of the <code>Context</code> between web
+ * requests.
  * </p>
  * 
  * <p>
- * This filter MUST appear BEFORE any other Acegi Security related filters,
- * because this filter WILL REMOVE any <code>Authentication</code> it finds in
- * the <code>SecurityContext</code>.
+ * This filter MUST be executed BEFORE any authentication procesing mechanisms.
+ * Authentication processing mechanisms (eg BASIC, CAS processing filters etc)
+ * expect the <code>ContextHolder</code> to contain a valid
+ * <code>SecureContext</code> by the time they execute.
  * </p>
  *
  * @author Ben Alex
  * @author Patrick Burleson
  * @version $Id$
  */
-public class HttpSessionContextIntegrationFilter implements Filter {
+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_AUTHENTICATION_CONTEXT_KEY = "ACEGI_SECURITY_AUTHENTICATION_CONTEXT";
+    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 false
@@ -109,6 +125,24 @@ public class HttpSessionContextIntegrationFilter implements Filter {
         return allowSessionCreation;
     }
 
+    public void setContext(Class secureContext) {
+        this.context = secureContext;
+    }
+
+    public Class getContext() {
+        return context;
+    }
+
+    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 net.sf.acegisecurity.context.SecurityContextImpl)");
+        }
+
+        this.contextObject = generateNewContext();
+    }
+
     /**
      * Does nothing. We use IoC container lifecycle services instead.
      */
@@ -124,18 +158,6 @@ public class HttpSessionContextIntegrationFilter implements Filter {
                 request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
             }
 
-            // Nullify the ThreadLocal if it currently contains data (it shouldn't)
-            if (SecurityContext.getAuthentication() != null) {
-                if (logger.isWarnEnabled()) {
-                    logger.warn(
-                        "SecurityContext should have been null but contained: '"
-                        + SecurityContext.getAuthentication()
-                        + "'; setting to null now");
-                }
-
-                SecurityContext.setAuthentication(null);
-            }
-
             HttpSession httpSession = null;
             boolean httpSessionExistedAtStartOfRequest = false;
 
@@ -146,47 +168,53 @@ public class HttpSessionContextIntegrationFilter implements Filter {
             if (httpSession != null) {
                 httpSessionExistedAtStartOfRequest = true;
 
-                Object authenticationObject = httpSession.getAttribute(ACEGI_SECURITY_AUTHENTICATION_CONTEXT_KEY);
+                Object contextObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);
 
-                if (authenticationObject != null) {
-                    // HttpSession provided an Authentication object
-                    if (authenticationObject instanceof Authentication) {
+                if (contextObject != null) {
+                    if (contextObject instanceof SecurityContext) {
                         if (logger.isDebugEnabled()) {
                             logger.debug(
-                                "Obtained from ACEGI_SECURITY_AUTHENTICATION_CONTEXT a valid Authentication and set to SecurityContext: '"
-                                + authenticationObject + "'");
+                                "Obtained from ACEGI_SECURITY_CONTEXT a valid SecurityContext and set to SecurityContextHolder: '"
+                                + contextObject + "'");
                         }
 
-                        SecurityContext.setAuthentication((Authentication) authenticationObject);
+                        SecurityContextHolder.setContext((SecurityContext) contextObject);
                     } else {
                         if (logger.isWarnEnabled()) {
                             logger.warn(
-                                "ACEGI_SECURITY_AUTHENTICATION_CONTEXT did not contain an Authentication but contained: '"
-                                + authenticationObject
-                                + "'; are you improperly modifying the HttpSession directly (you should always use SecurityContext) or using the HttpSession attribute reserved for this class?");
+                                "ACEGI_SECURITY_CONTEXT did not contain a SecurityContext but contained: '"
+                                + contextObject
+                                + "'; 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_AUTHENTICATION_CONTEXT");
+                            "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");
+                    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 any
-            // reference to the HttpSession laying around in memory (in case the
-            // chain.doFilter() we're about to invoke decides to invalidate it).
+            // 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
             chain.doFilter(request, response);
 
-            // Store Authentication back to HttpSession
+            // Store context back to HttpSession
             try {
                 httpSession = ((HttpServletRequest) request).getSession(false);
             } catch (IllegalStateException ignored) {}
@@ -194,21 +222,22 @@ public class HttpSessionContextIntegrationFilter implements Filter {
             if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {
                 if (logger.isDebugEnabled()) {
                     logger.debug(
-                        "HttpSession is now null, but was not null at start of request; session was invalidated during filter chain, so we will NOT create a new session now");
+                        "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 have to
+            // Generate a HttpSession only if we need to
             if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) {
                 if (!allowSessionCreation) {
                     if (logger.isDebugEnabled()) {
                         logger.debug(
-                            "The HttpSessionContextIntegrationFilter is prohibited from creating a HttpSession by the allowSessionCreation property being false");
+                            "The HttpSession is currently null, and the HttpSessionContextIntegrationFilter is prohibited from creating a HttpSession (because the allowSessionCreation property is false) - SecurityContext thus not stored for next request");
                     }
-                } else if (SecurityContext.getAuthentication() != null) {
+                } else if (!contextObject.equals(
+                        SecurityContextHolder.getContext())) {
                     if (logger.isDebugEnabled()) {
                         logger.debug(
-                            "HttpSession being created as SecurityContext contents are non-null");
+                            "HttpSession being created as SecurityContextHolder contents are non-default");
                     }
 
                     try {
@@ -217,32 +246,44 @@ public class HttpSessionContextIntegrationFilter implements Filter {
                 } else {
                     if (logger.isDebugEnabled()) {
                         logger.debug(
-                            "SecurityContext contents and HttpSession are both null; not creating HttpSession");
+                            "HttpSession is null, but SecurityContextHolder has not changed from default: ' "
+                            + SecurityContextHolder.getContext()
+                            + "'; not creating HttpSession or storing SecurityContextHolder contents");
                     }
                 }
             }
 
-            // If HttpSession exists or was just created, store current SecurityContext contents
+            // If HttpSession exists, store current SecurityContextHolder contents
             if (httpSession != null) {
-                httpSession.setAttribute(ACEGI_SECURITY_AUTHENTICATION_CONTEXT_KEY,
-                    SecurityContext.getAuthentication());
+                httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY,
+                    SecurityContextHolder.getContext());
 
                 if (logger.isDebugEnabled()) {
                     logger.debug("SecurityContext stored to HttpSession: '"
-                        + SecurityContext.getAuthentication() + "'");
+                        + SecurityContextHolder.getContext() + "'");
                 }
             }
 
-            // Remove SecurityContext contents, ready for next request
-            SecurityContext.setAuthentication(null);
+            // Remove SecurityContextHolder contents
+            SecurityContextHolder.setContext(generateNewContext());
 
             if (logger.isDebugEnabled()) {
                 logger.debug(
-                    "SecurityContext set to null as request processing completed");
+                    "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);
+        }
+    }
+
     /**
      * Does nothing. We use IoC container lifecycle services instead.
      *

+ 25 - 16
core/src/main/java/org/acegisecurity/context/SecurityContext.java

@@ -19,26 +19,35 @@ import net.sf.acegisecurity.Authentication;
 
 
 /**
- * Associates a given {@link Authentication} with the current execution thread,
- * along with new threads the current execution thread may spawn.
+ * Interface defining the minimum security information associated with the
+ * current thread of execution.
+ * 
+ * <p>
+ * Stored in {@link net.sf.acegisecurity.context.SecurityContextHolder}.
+ * </p>
  *
  * @author Ben Alex
  * @version $Id$
- *
- * @see java.lang.InheritableThreadLocal
  */
-public class SecurityContext {
-    //~ Static fields/initializers =============================================
-
-    private static InheritableThreadLocal authenticationHolder = new InheritableThreadLocal();
-
+public interface SecurityContext {
     //~ Methods ================================================================
 
-    public static void setAuthentication(Authentication authentication) {
-        authenticationHolder.set(authentication);
-    }
-
-    public static Authentication getAuthentication() {
-        return (Authentication) authenticationHolder.get();
-    }
+    /**
+     * Changes the currently authenticated principal, or removes the
+     * authentication information.
+     *
+     * @param authentication the new <code>Authentication</code> token, or
+     *        <code>null</code> if no further authentication information
+     *        should be stored
+     */
+    public void setAuthentication(Authentication authentication);
+
+    /**
+     * Obtains the currently authenticated principal, or an authentication
+     * request token.
+     *
+     * @return the <code>Authentication</code> or <code>null</code> if no
+     *         authentication information is available
+     */
+    public Authentication getAuthentication();
 }

+ 78 - 0
core/src/main/java/org/acegisecurity/context/SecurityContextHolder.java

@@ -0,0 +1,78 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+import org.springframework.util.Assert;
+
+
+/**
+ * Associates a given {@link SecurityContext} with the current execution
+ * thread, along with new threads the current execution thread may spawn.
+ * 
+ * <p>
+ * To guarantee the {@link #getContext()} never returns <code>null</code>, this
+ * class defaults to returning <code>SecurityContextImpl</code> if no
+ * <code>SecurityContext</code> has ever been associated with the current
+ * thread of execution. Despite this behaviour, in general another class will
+ * select the concrete <code>SecurityContext</code> implementation to use and
+ * expressly set an instance of that implementation against the
+ * <code>SecurityContextHolder</code>.
+ * </p>
+ *
+ * @author Ben Alex
+ * @version $Id$
+ *
+ * @see java.lang.InheritableThreadLocal
+ * @see net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter
+ */
+public class SecurityContextHolder {
+    //~ Static fields/initializers =============================================
+
+    private static InheritableThreadLocal contextHolder = new InheritableThreadLocal();
+
+    //~ Methods ================================================================
+
+    /**
+     * Associates a new <code>SecurityContext</code> with the current thread of
+     * execution.
+     *
+     * @param context the new <code>SecurityContext</code> (may not be
+     *        <code>null</code>)
+     */
+    public static void setContext(SecurityContext context) {
+        Assert.notNull(context,
+            "Only non-null SecurityContext instances are permitted");
+        contextHolder.set(context);
+    }
+
+    /**
+     * Obtains the <code>SecurityContext</code> associated with the current
+     * thread of execution. If no <code>SecurityContext</code> has been
+     * associated with the current thread of execution, a new instance of
+     * {@link SecurityContextImpl} is associated with the current thread and
+     * then returned.
+     *
+     * @return the current <code>SecurityContext</code> (guaranteed to never be
+     *         <code>null</code>)
+     */
+    public static SecurityContext getContext() {
+        if (contextHolder.get() == null) {
+            contextHolder.set(new SecurityContextImpl());
+        }
+
+        return (SecurityContext) contextHolder.get();
+    }
+}

+ 79 - 0
core/src/main/java/org/acegisecurity/context/SecurityContextImpl.java

@@ -0,0 +1,79 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+import net.sf.acegisecurity.Authentication;
+
+
+/**
+ * Base implementation of {@link SecurityContext}.
+ * 
+ * <p>
+ * Used by default by {@link
+ * net.sf.acegisecurity.context.SecurityContextHolder} and {@link
+ * net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter}.
+ * </p>
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class SecurityContextImpl implements SecurityContext {
+    //~ Instance fields ========================================================
+
+    private Authentication authentication;
+
+    //~ Methods ================================================================
+
+    public void setAuthentication(Authentication authentication) {
+        this.authentication = authentication;
+    }
+
+    public Authentication getAuthentication() {
+        return authentication;
+    }
+
+    public boolean equals(Object obj) {
+        if (obj instanceof SecurityContextImpl) {
+            SecurityContextImpl test = (SecurityContextImpl) obj;
+
+            if ((this.getAuthentication() == null)
+                && (test.getAuthentication() == null)) {
+                return true;
+            }
+
+            if ((this.getAuthentication() != null)
+                && (test.getAuthentication() != null)
+                && this.getAuthentication().equals(test.getAuthentication())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(super.toString());
+
+        if (this.authentication == null) {
+            sb.append(": Null authentication");
+        } else {
+            sb.append(": Authentication: " + this.authentication);
+        }
+
+        return sb.toString();
+    }
+}

+ 3 - 2
core/src/main/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java

@@ -17,7 +17,7 @@ package net.sf.acegisecurity.context.httpinvoker;
 
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.logging.Log;
@@ -86,7 +86,8 @@ public class AuthenticationSimpleHttpInvokerRequestExecutor
         throws IOException, AuthenticationCredentialsNotFoundException {
         super.prepareConnection(con, contentLength);
 
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         if ((auth != null) && (auth.getPrincipal() != null)
             && (auth.getCredentials() != null)) {

+ 0 - 4
core/src/main/java/org/acegisecurity/context/package.html

@@ -5,10 +5,6 @@ Provides a "request context".
 A request context is associated with the current execution thread. It holds
 objects that would otherwise need to be included in many method signatures, 
 such as for authentication.</p>
-
-<p><b>The majority of this package has been deprecated. Please use the
-<code>SecurityContext</code> and <code>HttpSessionContextIntegrationFilter</code>
-classes only.</b></p>
 </body>
 </html>
 

+ 20 - 17
core/src/main/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocation.java

@@ -15,8 +15,9 @@
 
 package net.sf.acegisecurity.context.rmi;
 
-import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 
 import org.aopalliance.intercept.MethodInvocation;
 
@@ -30,8 +31,8 @@ import java.lang.reflect.InvocationTargetException;
 
 /**
  * The actual <code>RemoteInvocation</code> that is passed from the client to
- * the server, which contains the contents of {@link SecurityContext}, being
- * an {@link Authentication} object.
+ * the server, which contains the contents of {@link SecurityContextHolder},
+ * being a {@link SecureContext} object.
  * 
  * <p>
  * When constructed on the client via {@link
@@ -39,11 +40,11 @@ import java.lang.reflect.InvocationTargetException;
  * the contents of the <code>SecurityContext</code> are stored inside the
  * object. The object is then passed to the server that is processing the
  * remote invocation. Upon the server invoking the remote invocation, it will
- * retrieve the passed contents of the <code>SecurityContext</code> and set
- * them to the server-side <code>SecurityContext</code> whilst the target
- * object is invoked. When the target invocation has been completed, the
- * server-side <code>SecurityContext</code> will be reset to
- * <code>null</code>.
+ * retrieve the passed contents of the <code>SecurityContextHolder</code> and
+ * set them to the server-side <code>SecurityContextHolder</code> whilst the
+ * target object is invoked. When the target invocation has been completed,
+ * the server-side <code>SecurityContextHolder</code> will be reset to a new
+ * instance of <code>SecurityContextImpl</code>.
  * </p>
  *
  * @author James Monaghan
@@ -57,23 +58,23 @@ public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
 
     //~ Instance fields ========================================================
 
-    private Authentication authentication;
+    private SecurityContext securityContext;
 
     //~ Constructors ===========================================================
 
     /**
      * Constructs the object, storing the value of the client-side
-     * <code>ContextHolder</code> inside the object.
+     * <code>SecurityContextHolder</code> inside the object.
      *
      * @param methodInvocation the method to invoke
      */
     public ContextPropagatingRemoteInvocation(MethodInvocation methodInvocation) {
         super(methodInvocation);
-        authentication = SecurityContext.getAuthentication();
+        securityContext = SecurityContextHolder.getContext();
 
         if (logger.isDebugEnabled()) {
-            logger.debug("RemoteInvocation now has authentication: "
-                + authentication);
+            logger.debug("RemoteInvocation now has SecurityContext: "
+                + securityContext);
         }
     }
 
@@ -94,18 +95,20 @@ public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
     public Object invoke(Object targetObject)
         throws NoSuchMethodException, IllegalAccessException, 
             InvocationTargetException {
-        SecurityContext.setAuthentication(authentication);
+        SecurityContextHolder.setContext(securityContext);
 
         if (logger.isDebugEnabled()) {
-            logger.debug("Set SecurityContext to contain: " + authentication);
+            logger.debug("Set SecurityContextHolder to contain: "
+                + securityContext);
         }
 
         Object result = super.invoke(targetObject);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
 
         if (logger.isDebugEnabled()) {
-            logger.debug("Set SecurityContext to null");
+            logger.debug(
+                "Set SecurityContext to new instance of SecurityContextImpl");
         }
 
         return result;

+ 14 - 12
core/src/main/java/org/acegisecurity/intercept/AbstractSecurityInterceptor.java

@@ -25,7 +25,7 @@ import net.sf.acegisecurity.AuthenticationManager;
 import net.sf.acegisecurity.ConfigAttribute;
 import net.sf.acegisecurity.ConfigAttributeDefinition;
 import net.sf.acegisecurity.RunAsManager;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.intercept.event.AuthenticationCredentialsNotFoundEvent;
 import net.sf.acegisecurity.intercept.event.AuthenticationFailureEvent;
 import net.sf.acegisecurity.intercept.event.AuthorizationFailureEvent;
@@ -328,7 +328,8 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
                     + token.getAuthentication().toString());
             }
 
-            SecurityContext.setAuthentication(token.getAuthentication());
+            SecurityContextHolder.getContext().setAuthentication(token
+                .getAuthentication());
         }
 
         if (afterInvocationManager != null) {
@@ -358,7 +359,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
 
             // We check for just the property we're interested in (we do
             // not call Context.validate() like the ContextInterceptor)
-            if (SecurityContext.getAuthentication() == null) {
+            if (SecurityContextHolder.getContext().getAuthentication() == null) {
                 credentialsNotFound("Authentication credentials were not found in the SecurityContext",
                     object, attr);
             }
@@ -367,11 +368,12 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
             Authentication authenticated;
 
             try {
-                authenticated = this.authenticationManager.authenticate(SecurityContext
-                        .getAuthentication());
+                authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext()
+                                                                                             .getAuthentication());
             } catch (AuthenticationException authenticationException) {
                 AuthenticationFailureEvent event = new AuthenticationFailureEvent(object,
-                        attr, SecurityContext.getAuthentication(),
+                        attr,
+                        SecurityContextHolder.getContext().getAuthentication(),
                         authenticationException);
                 this.context.publishEvent(event);
 
@@ -384,7 +386,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
                 logger.debug("Authenticated: " + authenticated.toString());
             }
 
-            SecurityContext.setAuthentication(authenticated);
+            SecurityContextHolder.getContext().setAuthentication(authenticated);
 
             // Attempt authorization
             try {
@@ -423,7 +425,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
                         + runAs.toString());
                 }
 
-                SecurityContext.setAuthentication(runAs);
+                SecurityContextHolder.getContext().setAuthentication(runAs);
 
                 return new InterceptorStatusToken(authenticated, true, attr,
                     object); // revert to token.Authenticated post-invocation
@@ -436,16 +438,16 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
             this.context.publishEvent(new PublicInvocationEvent(object));
 
             // Set Authentication object (if it exists) to be unauthenticated
-            if (SecurityContext.getAuthentication() != null) {
+            if (SecurityContextHolder.getContext().getAuthentication() != null) {
                 if (logger.isDebugEnabled()) {
                     logger.debug(
                         "Authentication object detected and tagged as unauthenticated");
                 }
 
-                Authentication authenticated = SecurityContext
-                    .getAuthentication();
+                Authentication authenticated = SecurityContextHolder.getContext()
+                                                                    .getAuthentication();
                 authenticated.setAuthenticated(false);
-                SecurityContext.setAuthentication(authenticated);
+                SecurityContextHolder.getContext().setAuthentication(authenticated);
             }
 
             return null; // no further work post-invocation

+ 2 - 2
core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java

@@ -20,7 +20,7 @@ import net.sf.acegisecurity.AuthenticationException;
 import net.sf.acegisecurity.AuthenticationTrustResolver;
 import net.sf.acegisecurity.AuthenticationTrustResolverImpl;
 import net.sf.acegisecurity.InsufficientAuthenticationException;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.ui.AbstractProcessingFilter;
 import net.sf.acegisecurity.util.PortResolver;
 import net.sf.acegisecurity.util.PortResolverImpl;
@@ -193,7 +193,7 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
             sendStartAuthentication(fi, authentication);
         } catch (AccessDeniedException accessDenied) {
             if (authenticationTrustResolver.isAnonymous(
-                    SecurityContext.getAuthentication())) {
+                    SecurityContextHolder.getContext().getAuthentication())) {
                 if (logger.isDebugEnabled()) {
                     logger.debug("Access is denied (user is anonymous); redirecting to authentication entry point",
                         accessDenied);

+ 10 - 7
core/src/main/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilter.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.providers.anonymous;
 
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.dao.memory.UserAttribute;
 
 import org.apache.commons.logging.Log;
@@ -131,19 +131,22 @@ public class AnonymousProcessingFilter implements Filter, InitializingBean {
     public void doFilter(ServletRequest request, ServletResponse response,
         FilterChain chain) throws IOException, ServletException {
         if (applyAnonymousForThisRequest(request)) {
-            if (SecurityContext.getAuthentication() == null) {
-                SecurityContext.setAuthentication(createAuthentication(request));
+            if (SecurityContextHolder.getContext().getAuthentication() == null) {
+                SecurityContextHolder.getContext().setAuthentication(createAuthentication(
+                        request));
 
                 if (logger.isDebugEnabled()) {
                     logger.debug(
-                        "Replaced ContextHolder with anonymous token: '"
-                        + SecurityContext.getAuthentication() + "'");
+                        "Replaced SecurityContextHolder with anonymous token: '"
+                        + SecurityContextHolder.getContext().getAuthentication()
+                        + "'");
                 }
             } else {
                 if (logger.isDebugEnabled()) {
                     logger.debug(
-                        "ContextHolder not replaced with anonymous token, as ContextHolder already contained: '"
-                        + SecurityContext.getAuthentication() + "'");
+                        "SecurityContextHolder not replaced with anonymous token, as ContextHolder already contained: '"
+                        + SecurityContextHolder.getContext().getAuthentication()
+                        + "'");
                 }
             }
         }

+ 2 - 2
core/src/main/java/org/acegisecurity/providers/jaas/SecureContextLoginModule.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.providers.jaas;
 
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -122,7 +122,7 @@ public class SecureContextLoginModule implements LoginModule {
      * @throws LoginException if the authentication fails
      */
     public boolean login() throws LoginException {
-        authen = SecurityContext.getAuthentication();
+        authen = SecurityContextHolder.getContext().getAuthentication();
 
         if (authen == null) {
             throw new LoginException("Authentication not found in security"

+ 5 - 4
core/src/main/java/org/acegisecurity/taglibs/authz/AclTag.java

@@ -19,7 +19,7 @@ import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.acl.AclEntry;
 import net.sf.acegisecurity.acl.AclManager;
 import net.sf.acegisecurity.acl.basic.AbstractBasicAclEntry;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -133,16 +133,17 @@ public class AclTag extends TagSupport {
             return Tag.EVAL_BODY_INCLUDE;
         }
 
-        if (SecurityContext.getAuthentication() == null) {
+        if (SecurityContextHolder.getContext().getAuthentication() == null) {
             if (logger.isDebugEnabled()) {
                 logger.debug(
-                    "SecurityContext did not return a non-null Authentication object, so skipping tag body");
+                    "SecurityContextHolder did not return a non-null Authentication object, so skipping tag body");
             }
 
             return Tag.SKIP_BODY;
         }
 
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         ApplicationContext context = getContext(pageContext);
         Map beans = context.getBeansOfType(AclManager.class, false, false);

+ 4 - 3
core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java

@@ -17,7 +17,7 @@ package net.sf.acegisecurity.taglibs.authz;
 
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import java.io.IOException;
 
@@ -68,11 +68,12 @@ public class AuthenticationTag extends TagSupport {
             throw new JspException("Unsupported use of auth:authentication tag");
         }
 
-        if (SecurityContext.getAuthentication() == null) {
+        if (SecurityContextHolder.getContext().getAuthentication() == null) {
             return Tag.SKIP_BODY;
         }
 
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         if (auth.getPrincipal() == null) {
             return Tag.SKIP_BODY;

+ 3 - 2
core/src/main/java/org/acegisecurity/taglibs/authz/AuthorizeTag.java

@@ -18,7 +18,7 @@ package net.sf.acegisecurity.taglibs.authz;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.springframework.util.StringUtils;
 
@@ -122,7 +122,8 @@ public class AuthorizeTag extends TagSupport {
     }
 
     private Collection getPrincipalAuthorities() {
-        Authentication currentUser = SecurityContext.getAuthentication();
+        Authentication currentUser = SecurityContextHolder.getContext()
+                                                          .getAuthentication();
 
         if (null == currentUser) {
             return Collections.EMPTY_LIST;

+ 6 - 5
core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java

@@ -18,7 +18,7 @@ package net.sf.acegisecurity.ui;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationException;
 import net.sf.acegisecurity.AuthenticationManager;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.ui.rememberme.NullRememberMeServices;
 import net.sf.acegisecurity.ui.rememberme.RememberMeServices;
 
@@ -369,11 +369,11 @@ public abstract class AbstractProcessingFilter implements Filter,
             logger.debug("Authentication success: " + authResult.toString());
         }
 
-        SecurityContext.setAuthentication(authResult);
+        SecurityContextHolder.getContext().setAuthentication(authResult);
 
         if (logger.isDebugEnabled()) {
             logger.debug(
-                "Updated ContextHolder to contain the following Authentication: '"
+                "Updated SecurityContextHolder to contain the following Authentication: '"
                 + authResult + "'");
         }
 
@@ -404,10 +404,11 @@ public abstract class AbstractProcessingFilter implements Filter,
     protected void unsuccessfulAuthentication(HttpServletRequest request,
         HttpServletResponse response, AuthenticationException failed)
         throws IOException {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         if (logger.isDebugEnabled()) {
-            logger.debug("Updated ContextHolder to contain null Authentication");
+            logger.debug(
+                "Updated SecurityContextHolder to contain null Authentication");
         }
 
         String failureUrl = exceptionMappings.getProperty(failed.getClass()

+ 3 - 3
core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java

@@ -18,7 +18,7 @@ package net.sf.acegisecurity.ui.basicauth;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationException;
 import net.sf.acegisecurity.AuthenticationManager;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 import net.sf.acegisecurity.ui.WebAuthenticationDetails;
@@ -187,7 +187,7 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
                         + " failed: " + failed.toString());
                 }
 
-                SecurityContext.setAuthentication(null);
+                SecurityContextHolder.getContext().setAuthentication(null);
                 authenticationEntryPoint.commence(request, response, failed);
 
                 return;
@@ -198,7 +198,7 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
                 logger.debug("Authentication success: " + authResult.toString());
             }
 
-            SecurityContext.setAuthentication(authResult);
+            SecurityContextHolder.getContext().setAuthentication(authResult);
         }
 
         chain.doFilter(request, response);

+ 3 - 3
core/src/main/java/org/acegisecurity/ui/digestauth/DigestProcessingFilter.java

@@ -19,7 +19,7 @@ import net.sf.acegisecurity.AuthenticationException;
 import net.sf.acegisecurity.AuthenticationServiceException;
 import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
 import net.sf.acegisecurity.providers.dao.UserCache;
@@ -371,7 +371,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean {
                     user.getPassword());
             authRequest.setDetails(new WebAuthenticationDetails(httpRequest));
 
-            SecurityContext.setAuthentication(authRequest);
+            SecurityContextHolder.getContext().setAuthentication(authRequest);
         }
 
         chain.doFilter(request, response);
@@ -436,7 +436,7 @@ public class DigestProcessingFilter implements Filter, InitializingBean {
 
     private void fail(ServletRequest request, ServletResponse response,
         AuthenticationException failed) throws IOException, ServletException {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         if (logger.isDebugEnabled()) {
             logger.debug(failed);

+ 11 - 8
core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java

@@ -15,7 +15,7 @@
 
 package net.sf.acegisecurity.ui.rememberme;
 
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -102,19 +102,22 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean {
         HttpServletRequest httpRequest = (HttpServletRequest) request;
         HttpServletResponse httpResponse = (HttpServletResponse) response;
 
-        if (SecurityContext.getAuthentication() == null) {
-            SecurityContext.setAuthentication(rememberMeServices.autoLogin(
-                    httpRequest, httpResponse));
+        if (SecurityContextHolder.getContext().getAuthentication() == null) {
+            SecurityContextHolder.getContext().setAuthentication(rememberMeServices
+                .autoLogin(httpRequest, httpResponse));
 
             if (logger.isDebugEnabled()) {
-                logger.debug("Replaced ContextHolder with remember-me token: '"
-                    + SecurityContext.getAuthentication() + "'");
+                logger.debug(
+                    "Replaced SecurityContextHolder with remember-me token: '"
+                    + SecurityContextHolder.getContext().getAuthentication()
+                    + "'");
             }
         } else {
             if (logger.isDebugEnabled()) {
                 logger.debug(
-                    "ContextHolder not replaced with remember-me token, as ContextHolder already contained: '"
-                    + SecurityContext.getAuthentication() + "'");
+                    "SecurityContextHolder not replaced with remember-me token, as SecurityContextHolder already contained: '"
+                    + SecurityContextHolder.getContext().getAuthentication()
+                    + "'");
             }
         }
 

+ 5 - 5
core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java

@@ -18,7 +18,7 @@ package net.sf.acegisecurity.ui.x509;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationException;
 import net.sf.acegisecurity.AuthenticationManager;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.x509.X509AuthenticationToken;
 import net.sf.acegisecurity.ui.AbstractProcessingFilter;
 import net.sf.acegisecurity.ui.WebAuthenticationDetails;
@@ -126,10 +126,10 @@ public class X509ProcessingFilter implements Filter, InitializingBean {
 
         if (logger.isDebugEnabled()) {
             logger.debug("Checking secure context token: "
-                + SecurityContext.getAuthentication());
+                + SecurityContextHolder.getContext().getAuthentication());
         }
 
-        if (SecurityContext.getAuthentication() == null) {
+        if (SecurityContextHolder.getContext().getAuthentication() == null) {
             Authentication authResult = null;
             X509Certificate clientCertificate = extractClientCertificate(httpRequest);
 
@@ -166,7 +166,7 @@ public class X509ProcessingFilter implements Filter, InitializingBean {
             logger.debug("Authentication success: " + authResult);
         }
 
-        SecurityContext.setAuthentication(authResult);
+        SecurityContextHolder.getContext().setAuthentication(authResult);
     }
 
     /**
@@ -179,7 +179,7 @@ public class X509ProcessingFilter implements Filter, InitializingBean {
      */
     protected void unsuccessfulAuthentication(HttpServletRequest request,
         HttpServletResponse response, AuthenticationException failed) {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         if (logger.isDebugEnabled()) {
             logger.debug("Updated ContextHolder to contain null Authentication");

+ 3 - 2
core/src/main/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapper.java

@@ -19,7 +19,7 @@ import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationTrustResolver;
 import net.sf.acegisecurity.AuthenticationTrustResolverImpl;
 import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import java.security.Principal;
 
@@ -116,7 +116,8 @@ public class ContextHolderAwareRequestWrapper extends HttpServletRequestWrapper
      * @return the authentication object or <code>null</code>
      */
     private Authentication getAuthentication() {
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         if (!authenticationTrustResolver.isAnonymous(auth)) {
             return auth;

+ 5 - 3
core/src/test/java/org/acegisecurity/TargetObject.java

@@ -15,7 +15,7 @@
 
 package net.sf.acegisecurity;
 
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 
 /**
@@ -47,7 +47,8 @@ public class TargetObject implements ITargetObject {
      *         <code>Authentication</code> object is authenticated or not
      */
     public String makeLowerCase(String input) {
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         if (auth == null) {
             return input.toLowerCase() + " Authentication empty";
@@ -69,7 +70,8 @@ public class TargetObject implements ITargetObject {
      *         <code>Authentication</code> object is authenticated or not
      */
     public String makeUpperCase(String input) {
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         return input.toUpperCase() + " " + auth.getClass().getName() + " "
         + auth.isAuthenticated();

+ 10 - 9
core/src/test/java/org/acegisecurity/adapters/HttpRequestIntegrationFilterTests.java

@@ -19,7 +19,7 @@ import junit.framework.TestCase;
 
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.util.MockFilterChain;
 
 import org.springframework.mock.web.MockHttpServletRequest;
@@ -63,13 +63,14 @@ public class HttpRequestIntegrationFilterTests extends TestCase {
 
         filter.doFilter(request, response, chain);
 
-        if (!(SecurityContext.getAuthentication() instanceof PrincipalAcegiUserToken)) {
-            System.out.println(SecurityContext.getAuthentication());
+        if (!(SecurityContextHolder.getContext().getAuthentication() instanceof PrincipalAcegiUserToken)) {
+            System.out.println(SecurityContextHolder.getContext()
+                                                    .getAuthentication());
             fail("Should have returned PrincipalAcegiUserToken");
         }
 
-        PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) SecurityContext
-            .getAuthentication();
+        PrincipalAcegiUserToken castResult = (PrincipalAcegiUserToken) SecurityContextHolder.getContext()
+                                                                                            .getAuthentication();
         assertEquals(principal, castResult);
     }
 
@@ -91,18 +92,18 @@ public class HttpRequestIntegrationFilterTests extends TestCase {
         MockHttpServletResponse response = new MockHttpServletResponse();
         MockFilterChain chain = new MockFilterChain(true);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         filter.doFilter(request, response, chain);
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     protected void setUp() throws Exception {
         super.setUp();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 }

+ 54 - 14
core/src/test/java/org/acegisecurity/context/HttpSessionContextIntegrationFilterTests.java

@@ -23,6 +23,8 @@ import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.MockFilterConfig;
 import net.sf.acegisecurity.adapters.PrincipalAcegiUserToken;
 import net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter;
+import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
@@ -60,6 +62,27 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
         junit.textui.TestRunner.run(HttpSessionContextIntegrationFilterTests.class);
     }
 
+    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 testExistingContextContentsCopiedIntoContextHolderFromSessionAndChangesToContextCopiedBackToSession()
         throws Exception {
         // Build an Authentication object we simulate came from HttpSession
@@ -72,10 +95,14 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
                 "someone", "password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("SOME_DIFFERENT_ROLE")});
 
+        // 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_AUTHENTICATION_CONTEXT_KEY,
-            sessionPrincipal);
+        request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
+            sc);
 
         MockHttpServletResponse response = new MockHttpServletResponse();
         FilterChain chain = new MockFilterChain(sessionPrincipal,
@@ -83,15 +110,18 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
 
         // 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
-        Authentication auth = (Authentication) request.getSession()
-                                                      .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_CONTEXT_KEY);
-        assertEquals(updatedPrincipal, auth);
+        SecurityContext context = (SecurityContext) request.getSession()
+                                                           .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
+        assertEquals(updatedPrincipal,
+            ((SecurityContext) context).getAuthentication());
     }
 
     public void testHttpSessionCreatedWhenContextHolderChanges()
@@ -108,15 +138,18 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
 
         // 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
-        Authentication auth = (Authentication) request.getSession(false)
-                                                      .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_CONTEXT_KEY);
-        assertEquals(updatedPrincipal, auth);
+        SecurityContext context = (SecurityContext) request.getSession(false)
+                                                           .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
+        assertEquals(updatedPrincipal,
+            ((SecurityContext) context).getAuthentication());
     }
 
     public void testHttpSessionNotCreatedUnlessContextHolderChanges()
@@ -128,6 +161,8 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
 
         // Prepare filter
         HttpSessionContextIntegrationFilter filter = new HttpSessionContextIntegrationFilter();
+        filter.setContext(SecurityContextImpl.class);
+        filter.afterPropertiesSet();
 
         // Execute filter
         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
@@ -146,7 +181,7 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
 
         // Build a mock request
         MockHttpServletRequest request = new MockHttpServletRequest();
-        request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_CONTEXT_KEY,
+        request.getSession().setAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY,
             "NOT_A_CONTEXT_OBJECT");
 
         MockHttpServletResponse response = new MockHttpServletResponse();
@@ -154,15 +189,18 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
 
         // 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
-        Authentication auth = (Authentication) request.getSession()
-                                                      .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_CONTEXT_KEY);
-        assertEquals(updatedPrincipal, auth);
+        SecurityContext context = (SecurityContext) request.getSession()
+                                                           .getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
+        assertEquals(updatedPrincipal,
+            ((SecurityContext) context).getAuthentication());
     }
 
     private void executeFilterInContainerSimulator(FilterConfig filterConfig,
@@ -191,11 +229,13 @@ public class HttpSessionContextIntegrationFilterTests extends TestCase {
             throws IOException, ServletException {
             if (expectedOnContextHolder != null) {
                 assertEquals(expectedOnContextHolder,
-                    SecurityContext.getAuthentication());
+                    SecurityContextHolder.getContext().getAuthentication());
             }
 
             if (changeContextHolder != null) {
-                SecurityContext.setAuthentication(changeContextHolder);
+                SecurityContext sc = SecurityContextHolder.getContext();
+                sc.setAuthentication(changeContextHolder);
+                SecurityContextHolder.setContext(sc);
             }
         }
     }

+ 19 - 16
core/src/test/java/org/acegisecurity/context/SecurityContextTests.java → core/src/test/java/org/acegisecurity/context/SecurityContextHolderTests.java

@@ -17,23 +17,21 @@ package net.sf.acegisecurity.context;
 
 import junit.framework.TestCase;
 
-import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
-
 
 /**
- * Tests {@link SecurityContext}.
+ * Tests {@link SecurityContextHolder}.
  *
  * @author Ben Alex
  * @version $Id$
  */
-public class SecurityContextTests extends TestCase {
+public class SecurityContextHolderTests extends TestCase {
     //~ Constructors ===========================================================
 
-    public SecurityContextTests() {
+    public SecurityContextHolderTests() {
         super();
     }
 
-    public SecurityContextTests(String arg0) {
+    public SecurityContextHolderTests(String arg0) {
         super(arg0);
     }
 
@@ -44,20 +42,25 @@ public class SecurityContextTests extends TestCase {
     }
 
     public static void main(String[] args) {
-        junit.textui.TestRunner.run(SecurityContextTests.class);
-    }
-
-    public void tearDown() {
-        SecurityContext.setAuthentication(null);
+        junit.textui.TestRunner.run(SecurityContextHolderTests.class);
     }
 
     public void testContextHolderGetterSetter() {
-        assertEquals(null, SecurityContext.getAuthentication());
+        SecurityContext sc = new SecurityContextImpl();
+        SecurityContextHolder.setContext(sc);
+        assertEquals(sc, SecurityContextHolder.getContext());
+    }
 
-        SecurityContext.setAuthentication(new UsernamePasswordAuthenticationToken(
-                "ben", "12345"));
+    public void testNeverReturnsNull() {
+        assertNotNull(SecurityContextHolder.getContext());
+    }
 
-        assertEquals("12345",
-            SecurityContext.getAuthentication().getCredentials());
+    public void testRejectsNulls() {
+        try {
+            SecurityContextHolder.setContext(null);
+            fail("Should have rejected null");
+        } catch (IllegalArgumentException expected) {
+            assertTrue(true);
+        }
     }
 }

+ 65 - 0
core/src/test/java/org/acegisecurity/context/SecurityContextImplTests.java

@@ -0,0 +1,65 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.context;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+
+
+/**
+ * Tests {@link SecurityContextImpl}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class SecurityContextImplTests extends TestCase {
+    //~ Constructors ===========================================================
+
+    public SecurityContextImplTests() {
+        super();
+    }
+
+    public SecurityContextImplTests(String arg0) {
+        super(arg0);
+    }
+
+    //~ Methods ================================================================
+
+    public final void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(SecurityContextImplTests.class);
+    }
+
+    public void testEmptyObjectsAreEquals() {
+        SecurityContextImpl obj1 = new SecurityContextImpl();
+        SecurityContextImpl obj2 = new SecurityContextImpl();
+        assertTrue(obj1.equals(obj2));
+    }
+
+    public void testSecurityContextCorrectOperation() {
+        SecurityContext context = new SecurityContextImpl();
+        Authentication auth = new UsernamePasswordAuthenticationToken("marissa",
+                "koala");
+        context.setAuthentication(auth);
+        assertEquals(auth, context.getAuthentication());
+        assertTrue(context.toString().lastIndexOf("marissa") != -1);
+    }
+}

+ 4 - 4
core/src/test/java/org/acegisecurity/context/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutorTests.java

@@ -18,7 +18,7 @@ package net.sf.acegisecurity.context.httpinvoker;
 import junit.framework.TestCase;
 
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.context.httpinvoker.AuthenticationSimpleHttpInvokerRequestExecutor;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
@@ -59,7 +59,7 @@ public class AuthenticationSimpleHttpInvokerRequestExecutorTests
         // Setup client-side context
         Authentication clientSideAuthentication = new UsernamePasswordAuthenticationToken("Aladdin",
                 "open sesame");
-        SecurityContext.setAuthentication(clientSideAuthentication);
+        SecurityContextHolder.getContext().setAuthentication(clientSideAuthentication);
 
         // Create a connection and ensure our executor sets its
         // properties correctly
@@ -74,11 +74,11 @@ public class AuthenticationSimpleHttpInvokerRequestExecutorTests
         assertEquals("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
             conn.getRequestProperty("Authorization"));
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testNullContextHolderIsNull() throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         // Create a connection and ensure our executor sets its
         // properties correctly

+ 6 - 5
core/src/test/java/org/acegisecurity/context/rmi/ContextPropagatingRemoteInvocationTests.java

@@ -20,7 +20,8 @@ import junit.framework.TestCase;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.MockMethodInvocation;
 import net.sf.acegisecurity.TargetObject;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.context.rmi.ContextPropagatingRemoteInvocation;
 import net.sf.acegisecurity.context.rmi.ContextPropagatingRemoteInvocationFactory;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
@@ -58,14 +59,14 @@ public class ContextPropagatingRemoteInvocationTests extends TestCase {
         // Setup client-side context
         Authentication clientSideAuthentication = new UsernamePasswordAuthenticationToken("marissa",
                 "koala");
-        SecurityContext.setAuthentication(clientSideAuthentication);
+        SecurityContextHolder.getContext().setAuthentication(clientSideAuthentication);
 
         ContextPropagatingRemoteInvocation remoteInvocation = getRemoteInvocation();
 
         // Set to null, as ContextPropagatingRemoteInvocation already obtained
         // a copy and nulling is necessary to ensure the Context delivered by
         // ContextPropagatingRemoteInvocation is used on server-side
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
 
         // The result from invoking the TargetObject should contain the
         // Authentication class delivered via the ContextHolder
@@ -75,10 +76,10 @@ public class ContextPropagatingRemoteInvocationTests extends TestCase {
 
     public void testNullContextHolderDoesNotCauseInvocationProblems()
         throws Exception {
-        SecurityContext.setAuthentication(null); // just to be explicit
+        SecurityContextHolder.getContext().setAuthentication(null); // just to be explicit
 
         ContextPropagatingRemoteInvocation remoteInvocation = getRemoteInvocation();
-        SecurityContext.setAuthentication(null); // unnecessary, but for explicitness
+        SecurityContextHolder.getContext().setAuthentication(null); // unnecessary, but for explicitness
 
         assertEquals("some_string Authentication empty",
             remoteInvocation.invoke(new TargetObject()));

+ 5 - 5
core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionAttributesTests.java

@@ -27,7 +27,7 @@ import net.sf.acegisecurity.OtherTargetObject;
 import net.sf.acegisecurity.SecurityConfig;
 import net.sf.acegisecurity.TargetObject;
 import net.sf.acegisecurity.acl.basic.SomeDomain;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
 import org.springframework.context.ApplicationContext;
@@ -168,14 +168,14 @@ public class MethodDefinitionAttributesTests extends TestCase {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_INTERFACE_METHOD_MAKE_UPPER_CASE")});
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         ITargetObject target = makeInterceptedTarget();
         String result = target.makeUpperCase("hello");
         assertEquals("HELLO net.sf.acegisecurity.MockRunAsAuthenticationToken true",
             result);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testMethodCallWithoutRunAsReplacement()
@@ -183,7 +183,7 @@ public class MethodDefinitionAttributesTests extends TestCase {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_INTERFACE_METHOD_MAKE_LOWER_CASE")});
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         ITargetObject target = makeInterceptedTarget();
         String result = target.makeLowerCase("HELLO");
@@ -191,7 +191,7 @@ public class MethodDefinitionAttributesTests extends TestCase {
         assertEquals("hello net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken true",
             result);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testNullReturnedIfZeroAttributesDefinedForMethodInvocation()

+ 12 - 12
core/src/test/java/org/acegisecurity/intercept/method/aopalliance/MethodSecurityInterceptorTests.java

@@ -33,7 +33,7 @@ import net.sf.acegisecurity.MockAfterInvocationManager;
 import net.sf.acegisecurity.MockAuthenticationManager;
 import net.sf.acegisecurity.MockRunAsManager;
 import net.sf.acegisecurity.RunAsManager;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.intercept.method.AbstractMethodDefinitionSource;
 import net.sf.acegisecurity.intercept.method.MockMethodDefinitionSource;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
@@ -80,7 +80,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
         String result = target.publicMakeLowerCase("HELLO");
         assertEquals("hello Authentication empty", result);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testCallingAPublicMethodWhenPresentingAnAuthenticationObjectWillProperlySetItsIsAuthenticatedProperty()
@@ -89,21 +89,21 @@ public class MethodSecurityInterceptorTests extends TestCase {
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_THIS_IS_NOT_REQUIRED_AS_IT_IS_PUBLIC")});
         assertTrue(!token.isAuthenticated());
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         ITargetObject target = makeInterceptedTarget();
         String result = target.publicMakeLowerCase("HELLO");
         assertEquals("hello net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken false",
             result);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testDeniesWhenAppropriate() throws Exception {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_NO_BENEFIT_TO_THIS_GRANTED_AUTHORITY")});
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         ITargetObject target = makeInterceptedTarget();
 
@@ -114,7 +114,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
             assertTrue(true);
         }
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testGetters() {
@@ -143,14 +143,14 @@ public class MethodSecurityInterceptorTests extends TestCase {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_UPPER")});
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         ITargetObject target = makeInterceptedTarget();
         String result = target.makeUpperCase("hello");
         assertEquals("HELLO net.sf.acegisecurity.MockRunAsAuthenticationToken true",
             result);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testMethodCallWithoutRunAsReplacement()
@@ -159,7 +159,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_LOWER")});
         assertTrue(!token.isAuthenticated());
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         ITargetObject target = makeInterceptedTargetWithoutAnAfterInvocationManager();
         String result = target.makeLowerCase("HELLO");
@@ -168,7 +168,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
         assertEquals("hello net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken true",
             result);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testRejectionOfEmptySecurityContext() throws Exception {
@@ -206,7 +206,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_LOWER")});
         assertTrue(!token.isAuthenticated());
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         ITargetObject target = makeInterceptedTargetRejectsAuthentication();
 
@@ -217,7 +217,7 @@ public class MethodSecurityInterceptorTests extends TestCase {
             assertTrue(true);
         }
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testRejectsCallsWhenObjectDefinitionSourceDoesNotSupportObject()

+ 5 - 5
core/src/test/java/org/acegisecurity/intercept/method/aspectj/AspectJSecurityInterceptorTests.java

@@ -26,7 +26,7 @@ import net.sf.acegisecurity.MockAuthenticationManager;
 import net.sf.acegisecurity.MockJoinPoint;
 import net.sf.acegisecurity.MockRunAsManager;
 import net.sf.acegisecurity.TargetObject;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.intercept.method.MethodDefinitionMap;
 import net.sf.acegisecurity.intercept.method.MethodDefinitionSourceEditor;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
@@ -86,7 +86,7 @@ public class AspectJSecurityInterceptorTests extends TestCase {
 
         MockAspectJCallback aspectJCallback = new MockAspectJCallback();
 
-        SecurityContext.setAuthentication(new TestingAuthenticationToken(
+        SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(
                 "marissa", "koala",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_ONE")}));
 
@@ -94,7 +94,7 @@ public class AspectJSecurityInterceptorTests extends TestCase {
 
         assertEquals("object proceeded", result);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testCallbackIsNotInvokedWhenPermissionDenied()
@@ -122,7 +122,7 @@ public class AspectJSecurityInterceptorTests extends TestCase {
         MockAspectJCallback aspectJCallback = new MockAspectJCallback();
         aspectJCallback.setThrowExceptionIfInvoked(true);
 
-        SecurityContext.setAuthentication(new TestingAuthenticationToken(
+        SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(
                 "marissa", "koala", new GrantedAuthority[] {}));
 
         try {
@@ -132,7 +132,7 @@ public class AspectJSecurityInterceptorTests extends TestCase {
             assertTrue(true);
         }
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     //~ Inner Classes ==========================================================

+ 6 - 5
core/src/test/java/org/acegisecurity/intercept/web/FilterSecurityInterceptorTests.java

@@ -30,7 +30,8 @@ import net.sf.acegisecurity.MockAuthenticationManager;
 import net.sf.acegisecurity.MockRunAsManager;
 import net.sf.acegisecurity.RunAsManager;
 import net.sf.acegisecurity.SecurityConfig;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
 import org.springframework.mock.web.MockHttpServletRequest;
@@ -170,14 +171,14 @@ public class FilterSecurityInterceptorTests extends TestCase {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_OK")});
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         // Create and test our secure object
         FilterInvocation fi = new FilterInvocation(request, response, chain);
         interceptor.invoke(fi);
 
         // Destroy the Context
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     public void testNormalStartupAndGetter() throws Exception {
@@ -228,14 +229,14 @@ public class FilterSecurityInterceptorTests extends TestCase {
         UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test",
                 "Password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("MOCK_OK")});
-        SecurityContext.setAuthentication(token);
+        SecurityContextHolder.getContext().setAuthentication(token);
 
         // Create and test our secure object
         FilterInvocation fi = new FilterInvocation(request, response, chain);
         interceptor.invoke(fi);
 
         // Destroy the Context
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     //~ Inner Classes ==========================================================

+ 5 - 4
core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java

@@ -23,7 +23,8 @@ import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.MockAuthenticationEntryPoint;
 import net.sf.acegisecurity.MockPortResolver;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationToken;
 import net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
 
@@ -83,7 +84,7 @@ public class SecurityEnforcementFilterTests extends TestCase {
                 false, false, false);
 
         // Setup ContextHolder, as filter needs to check if user is anonymous
-        SecurityContext.setAuthentication(new AnonymousAuthenticationToken(
+        SecurityContextHolder.getContext().setAuthentication(new AnonymousAuthenticationToken(
                 "ignored", "ignored",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("IGNORED")}));
 
@@ -113,7 +114,7 @@ public class SecurityEnforcementFilterTests extends TestCase {
                 false, false, false);
 
         // Setup ContextHolder, as filter needs to check if user is anonymous
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         // Test
         SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
@@ -356,7 +357,7 @@ public class SecurityEnforcementFilterTests extends TestCase {
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     //~ Inner Classes ==========================================================

+ 9 - 6
core/src/test/java/org/acegisecurity/providers/anonymous/AnonymousProcessingFilterTests.java

@@ -21,7 +21,8 @@ import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.MockFilterConfig;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 import net.sf.acegisecurity.providers.dao.memory.UserAttribute;
 
@@ -109,7 +110,7 @@ public class AnonymousProcessingFilterTests extends TestCase {
         Authentication originalAuth = new TestingAuthenticationToken("user",
                 "password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
-        SecurityContext.setAuthentication(originalAuth);
+        SecurityContextHolder.getContext().setAuthentication(originalAuth);
 
         // Setup our filter correctly
         UserAttribute user = new UserAttribute();
@@ -128,7 +129,8 @@ public class AnonymousProcessingFilterTests extends TestCase {
             request, new MockHttpServletResponse(), new MockFilterChain(true));
 
         // Ensure filter didn't change our original object
-        assertEquals(originalAuth, SecurityContext.getAuthentication());
+        assertEquals(originalAuth,
+            SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testOperationWhenNoAuthenticationInContextHolder()
@@ -147,7 +149,8 @@ public class AnonymousProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
             request, new MockHttpServletResponse(), new MockFilterChain(true));
 
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
         assertEquals("anonymousUsername", auth.getPrincipal());
         assertEquals(new GrantedAuthorityImpl("ROLE_ANONYMOUS"),
             auth.getAuthorities()[0]);
@@ -155,12 +158,12 @@ public class AnonymousProcessingFilterTests extends TestCase {
 
     protected void setUp() throws Exception {
         super.setUp();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     private void executeFilterInContainerSimulator(FilterConfig filterConfig,

+ 8 - 7
core/src/test/java/org/acegisecurity/providers/jaas/SecureContextLoginModuleTest.java

@@ -17,7 +17,8 @@ package net.sf.acegisecurity.providers.jaas;
 
 import junit.framework.TestCase;
 
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
 import java.util.HashSet;
@@ -44,7 +45,7 @@ public class SecureContextLoginModuleTest extends TestCase {
 
     public void testAbort() throws Exception {
         assertFalse("Should return false, no auth is set", module.abort());
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
         module.login();
         module.commit();
         assertTrue(module.abort());
@@ -59,7 +60,7 @@ public class SecureContextLoginModuleTest extends TestCase {
     }
 
     public void testLoginSuccess() throws Exception {
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
         assertTrue("Login should succeed, there is an authentication set",
             module.login());
         assertTrue("The authentication is not null, this should return true",
@@ -69,7 +70,7 @@ public class SecureContextLoginModuleTest extends TestCase {
     }
 
     public void testLogout() throws Exception {
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
         module.login();
         assertTrue("Should return true as it succeeds", module.logout());
         assertEquals("Authentication should be null", null,
@@ -81,7 +82,7 @@ public class SecureContextLoginModuleTest extends TestCase {
 
     public void testNullAuthenticationInSecureContext()
         throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
         assertFalse("Should return false and ask to be ignored", module.login());
     }
 
@@ -92,11 +93,11 @@ public class SecureContextLoginModuleTest extends TestCase {
     protected void setUp() throws Exception {
         module = new SecureContextLoginModule();
         module.initialize(subject, null, null, null);
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     protected void tearDown() throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
         module = null;
     }
 }

+ 17 - 17
core/src/test/java/org/acegisecurity/taglibs/authz/AclTagTests.java

@@ -25,7 +25,7 @@ import net.sf.acegisecurity.acl.AclEntry;
 import net.sf.acegisecurity.acl.AclManager;
 import net.sf.acegisecurity.acl.basic.MockAclObjectIdentity;
 import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import org.springframework.context.ApplicationContext;
@@ -53,34 +53,34 @@ public class AclTagTests extends TestCase {
         throws JspException {
         Authentication auth = new TestingAuthenticationToken("marissa",
                 "koala", new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         aclTag.setHasPermission(new Long(SimpleAclEntry.ADMINISTRATION)
             .toString());
         aclTag.setDomainObject(new Integer(54));
         assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testInclusionDeniedWhenNoListOfPermissionsGiven()
         throws JspException {
         Authentication auth = new TestingAuthenticationToken("marissa",
                 "koala", new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         aclTag.setHasPermission(null);
         aclTag.setDomainObject("object1");
         assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testInclusionDeniedWhenPrincipalDoesNotHoldAnyPermissions()
         throws JspException {
         Authentication auth = new TestingAuthenticationToken("john", "crow",
                 new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         aclTag.setHasPermission(new Integer(SimpleAclEntry.ADMINISTRATION)
             + "," + new Integer(SimpleAclEntry.READ));
@@ -90,32 +90,32 @@ public class AclTagTests extends TestCase {
         assertEquals("object1", aclTag.getDomainObject());
         assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testInclusionDeniedWhenPrincipalDoesNotHoldRequiredPermissions()
         throws JspException {
         Authentication auth = new TestingAuthenticationToken("marissa",
                 "koala", new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         aclTag.setHasPermission(new Integer(SimpleAclEntry.DELETE).toString());
         aclTag.setDomainObject("object1");
         assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testInclusionDeniedWhenSecurityContextEmpty()
         throws JspException {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         aclTag.setHasPermission(new Long(SimpleAclEntry.ADMINISTRATION)
             .toString());
         aclTag.setDomainObject("object1");
         assertEquals(Tag.SKIP_BODY, aclTag.doStartTag());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testInclusionPermittedWhenDomainObjectIsNull()
@@ -129,7 +129,7 @@ public class AclTagTests extends TestCase {
         throws JspException {
         Authentication auth = new TestingAuthenticationToken("john", "crow",
                 new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         aclTag.setHasPermission("0,5, 6"); // shouldn't be any space
 
@@ -140,34 +140,34 @@ public class AclTagTests extends TestCase {
             assertTrue(true);
         }
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testOperationWhenPrincipalHoldsPermissionOfMultipleList()
         throws JspException {
         Authentication auth = new TestingAuthenticationToken("marissa",
                 "koala", new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         aclTag.setHasPermission(new Integer(SimpleAclEntry.ADMINISTRATION)
             + "," + new Integer(SimpleAclEntry.READ));
         aclTag.setDomainObject("object1");
         assertEquals(Tag.EVAL_BODY_INCLUDE, aclTag.doStartTag());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testOperationWhenPrincipalHoldsPermissionOfSingleList()
         throws JspException {
         Authentication auth = new TestingAuthenticationToken("marissa",
                 "koala", new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         aclTag.setHasPermission(new Integer(SimpleAclEntry.READ).toString());
         aclTag.setDomainObject("object1");
         assertEquals(Tag.EVAL_BODY_INCLUDE, aclTag.doStartTag());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     //~ Inner Classes ==========================================================

+ 6 - 6
core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java

@@ -19,7 +19,7 @@ import junit.framework.TestCase;
 
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.GrantedAuthority;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 import net.sf.acegisecurity.providers.dao.User;
 
@@ -43,7 +43,7 @@ public class AuthenticationTagTests extends TestCase {
     public void testOperationWhenPrincipalIsAString() throws JspException {
         Authentication auth = new TestingAuthenticationToken("marissaAsString",
                 "koala", new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         authenticationTag.setOperation("principal");
         assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
@@ -56,7 +56,7 @@ public class AuthenticationTagTests extends TestCase {
                     "marissaUserDetails", "koala", true, true, true, true,
                     new GrantedAuthority[] {}), "koala",
                 new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         authenticationTag.setOperation("principal");
         assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
@@ -66,7 +66,7 @@ public class AuthenticationTagTests extends TestCase {
     public void testOperationWhenPrincipalIsNull() throws JspException {
         Authentication auth = new TestingAuthenticationToken(null, "koala",
                 new GrantedAuthority[] {});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         authenticationTag.setOperation("principal");
         assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
@@ -74,13 +74,13 @@ public class AuthenticationTagTests extends TestCase {
 
     public void testOperationWhenSecurityContextIsNull()
         throws JspException {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         authenticationTag.setOperation("principal");
         assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
         assertEquals(null, authenticationTag.getLastMessage());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testSkipsBodyIfNullOrEmptyOperation() throws Exception {

+ 4 - 3
core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagAttributeTests.java

@@ -19,7 +19,8 @@ import junit.framework.TestCase;
 
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import javax.servlet.jsp.JspException;
@@ -93,10 +94,10 @@ public class AuthorizeTagAttributeTests extends TestCase {
                         "ROLE_SUPERVISOR"), new GrantedAuthorityImpl(
                         "ROLE_RESTRICTED"),});
 
-        SecurityContext.setAuthentication(currentUser);
+        SecurityContextHolder.getContext().setAuthentication(currentUser);
     }
 
     protected void tearDown() throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 }

+ 5 - 4
core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagCustomGrantedAuthorityTests.java

@@ -18,7 +18,8 @@ package net.sf.acegisecurity.taglibs.authz;
 import junit.framework.TestCase;
 
 import net.sf.acegisecurity.GrantedAuthority;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import javax.servlet.jsp.JspException;
@@ -49,7 +50,7 @@ public class AuthorizeTagCustomGrantedAuthorityTests extends TestCase {
     public void testRejectsRequestWhenCustomAuthorityReturnsNull()
         throws JspException {
         authorizeTag.setIfAnyGranted("ROLE_TELLER");
-        SecurityContext.setAuthentication(new TestingAuthenticationToken(
+        SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(
                 "abc", "123",
                 new GrantedAuthority[] {new CustomGrantedAuthority(null)}));
 
@@ -68,11 +69,11 @@ public class AuthorizeTagCustomGrantedAuthorityTests extends TestCase {
                 new GrantedAuthority[] {new CustomGrantedAuthority(
                         "ROLE_TELLER")});
 
-        SecurityContext.setAuthentication(currentUser);
+        SecurityContextHolder.getContext().setAuthentication(currentUser);
     }
 
     protected void tearDown() throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     //~ Inner Classes ==========================================================

+ 4 - 3
core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagExpressionLanguageTests.java

@@ -19,7 +19,8 @@ import junit.framework.TestCase;
 
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import org.springframework.mock.web.MockPageContext;
@@ -76,10 +77,10 @@ public class AuthorizeTagExpressionLanguageTests extends TestCase {
         currentUser = new TestingAuthenticationToken("abc", "123",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TELLER"),});
 
-        SecurityContext.setAuthentication(currentUser);
+        SecurityContextHolder.getContext().setAuthentication(currentUser);
     }
 
     protected void tearDown() throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 }

+ 6 - 5
core/src/test/java/org/acegisecurity/taglibs/authz/AuthorizeTagTests.java

@@ -19,7 +19,8 @@ import junit.framework.TestCase;
 
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import javax.servlet.jsp.JspException;
@@ -42,7 +43,7 @@ public class AuthorizeTagTests extends TestCase {
 
     public void testAlwaysReturnsUnauthorizedIfNoUserFound()
         throws JspException {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         authorizeTag.setIfAllGranted("ROLE_TELLER");
         assertEquals("prevents request - no principal in Context",
@@ -80,7 +81,7 @@ public class AuthorizeTagTests extends TestCase {
 
     public void testPreventsBodyOutputIfNoSecureContext()
         throws JspException {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
         authorizeTag.setIfAnyGranted("ROLE_BANKER");
 
         assertEquals("prevents output - no context defined", Tag.SKIP_BODY,
@@ -115,10 +116,10 @@ public class AuthorizeTagTests extends TestCase {
                         "ROLE_SUPERVISOR"), new GrantedAuthorityImpl(
                         "ROLE_TELLER"),});
 
-        SecurityContext.setAuthentication(currentUser);
+        SecurityContextHolder.getContext().setAuthentication(currentUser);
     }
 
     protected void tearDown() throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 }

+ 18 - 14
core/src/test/java/org/acegisecurity/ui/AbstractProcessingFilterTests.java

@@ -24,7 +24,8 @@ import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.MockAuthenticationManager;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 import net.sf.acegisecurity.ui.rememberme.TokenBasedRememberMeServices;
 
@@ -129,7 +130,7 @@ public class AbstractProcessingFilterTests extends TestCase {
             chain);
 
         assertEquals("/myApp/failed.jsp", response.getRedirectedUrl());
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
 
         //Prepare again, this time using the exception mapping
         filter = new MockAbstractProcessingFilter(new AccountExpiredException(
@@ -147,7 +148,7 @@ public class AbstractProcessingFilterTests extends TestCase {
             chain);
 
         assertEquals("/myApp/accountExpired.jsp", response.getRedirectedUrl());
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testFilterProcessesUrlVariationsRespected()
@@ -173,9 +174,10 @@ public class AbstractProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
         assertEquals("/logged_in.jsp", response.getRedirectedUrl());
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals("test",
-            SecurityContext.getAuthentication().getPrincipal().toString());
+            SecurityContextHolder.getContext().getAuthentication().getPrincipal()
+                                 .toString());
     }
 
     public void testGettersSetters() {
@@ -247,9 +249,10 @@ public class AbstractProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
         assertEquals("/logged_in.jsp", response.getRedirectedUrl());
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals("test",
-            SecurityContext.getAuthentication().getPrincipal().toString());
+            SecurityContextHolder.getContext().getAuthentication().getPrincipal()
+                                 .toString());
     }
 
     public void testStartupDetectsInvalidAuthenticationFailureUrl()
@@ -338,9 +341,10 @@ public class AbstractProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
         assertEquals("/logged_in.jsp", response.getRedirectedUrl());
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals("test",
-            SecurityContext.getAuthentication().getPrincipal().toString());
+            SecurityContextHolder.getContext().getAuthentication().getPrincipal()
+                                 .toString());
 
         // Now try again but this time have filter deny access
         // Setup our HTTP request
@@ -356,7 +360,7 @@ public class AbstractProcessingFilterTests extends TestCase {
         // Test
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testSuccessfulAuthenticationButWithAlwaysUseDefaultTargetUrlCausesRedirectToDefaultTargetUrl()
@@ -385,7 +389,7 @@ public class AbstractProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
         assertEquals("/foobar", response.getRedirectedUrl());
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testSuccessfulAuthenticationCausesRedirectToSessionSpecifiedUrl()
@@ -410,17 +414,17 @@ public class AbstractProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
         assertEquals("/my-destination", response.getRedirectedUrl());
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     protected void setUp() throws Exception {
         super.setUp();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     private MockHttpServletRequest createMockRequest() {

+ 15 - 14
core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java

@@ -21,7 +21,8 @@ import net.sf.acegisecurity.MockAuthenticationEntryPoint;
 import net.sf.acegisecurity.MockAuthenticationManager;
 import net.sf.acegisecurity.MockFilterConfig;
 import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 
 import org.apache.commons.codec.binary.Base64;
 
@@ -115,7 +116,7 @@ public class BasicProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testGettersSetters() {
@@ -154,7 +155,7 @@ public class BasicProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testNormalOperation() throws Exception {
@@ -182,10 +183,10 @@ public class BasicProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals("marissa",
-            ((UserDetails) SecurityContext.getAuthentication().getPrincipal())
-            .getUsername());
+            ((UserDetails) SecurityContextHolder.getContext().getAuthentication()
+                                                .getPrincipal()).getUsername());
     }
 
     public void testOtherAuthorizationSchemeIsIgnored()
@@ -212,7 +213,7 @@ public class BasicProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testStartupDetectsMissingAuthenticationEntryPoint()
@@ -268,10 +269,10 @@ public class BasicProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals("marissa",
-            ((UserDetails) SecurityContext.getAuthentication().getPrincipal())
-            .getUsername());
+            ((UserDetails) SecurityContextHolder.getContext().getAuthentication()
+                                                .getPrincipal()).getUsername());
 
         // NOW PERFORM FAILED AUTHENTICATION
         // Setup our HTTP request
@@ -289,7 +290,7 @@ public class BasicProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -318,18 +319,18 @@ public class BasicProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
     protected void setUp() throws Exception {
         super.setUp();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     private void executeFilterInContainerSimulator(FilterConfig filterConfig,

+ 21 - 20
core/src/test/java/org/acegisecurity/ui/digestauth/DigestProcessingFilterTests.java

@@ -20,7 +20,8 @@ import junit.framework.TestCase;
 import net.sf.acegisecurity.DisabledException;
 import net.sf.acegisecurity.MockFilterConfig;
 import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
 import net.sf.acegisecurity.providers.dao.UserCache;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
@@ -141,7 +142,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
 
         String header = response.getHeader("WWW-Authenticate").toString()
@@ -175,7 +176,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testGettersSetters() {
@@ -220,7 +221,7 @@ public class DigestProcessingFilterTests extends TestCase {
             chain);
         assertEquals(401, response.getStatus());
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testMalformedHeaderReturnsForbidden() throws Exception {
@@ -246,7 +247,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -289,7 +290,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -333,7 +334,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -377,7 +378,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -421,7 +422,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -463,9 +464,9 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals("marissa",
-            ((UserDetails) SecurityContext.getAuthentication().getPrincipal())
+            ((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal())
             .getUsername());
     }
 
@@ -493,7 +494,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testStartupDetectsMissingAuthenticationDao()
@@ -561,7 +562,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNotNull(SecurityContext.getAuthentication());
+        assertNotNull(SecurityContextHolder.getContext().getAuthentication());
 
         // Now retry, giving an invalid nonce
         password = "WRONG_PASSWORD";
@@ -576,7 +577,7 @@ public class DigestProcessingFilterTests extends TestCase {
             chain);
 
         // Check we lost our previous authentication
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -619,7 +620,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -661,7 +662,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -703,7 +704,7 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
@@ -745,18 +746,18 @@ public class DigestProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(config, filter, request, response,
             chain);
 
-        assertNull(SecurityContext.getAuthentication());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
         assertEquals(401, response.getStatus());
     }
 
     protected void setUp() throws Exception {
         super.setUp();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     private String createAuthorizationHeader(String username, String realm,

+ 11 - 7
core/src/test/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilterTests.java

@@ -21,7 +21,8 @@ import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.MockFilterConfig;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import org.springframework.mock.web.MockHttpServletRequest;
@@ -121,7 +122,7 @@ public class RememberMeProcessingFilterTests extends TestCase {
         Authentication originalAuth = new TestingAuthenticationToken("user",
                 "password",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
-        SecurityContext.setAuthentication(originalAuth);
+        SecurityContextHolder.getContext().setAuthentication(originalAuth);
 
         // Setup our filter correctly
         Authentication remembered = new TestingAuthenticationToken("remembered",
@@ -138,7 +139,8 @@ public class RememberMeProcessingFilterTests extends TestCase {
             request, new MockHttpServletResponse(), new MockFilterChain(true));
 
         // Ensure filter didn't change our original object
-        assertEquals(originalAuth, SecurityContext.getAuthentication());
+        assertEquals(originalAuth,
+            SecurityContextHolder.getContext().getAuthentication());
     }
 
     public void testOperationWhenNoAuthenticationInContextHolder()
@@ -155,20 +157,22 @@ public class RememberMeProcessingFilterTests extends TestCase {
         executeFilterInContainerSimulator(new MockFilterConfig(), filter,
             request, new MockHttpServletResponse(), new MockFilterChain(true));
 
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         // Ensure filter setup with our remembered authentication object
-        assertEquals(remembered, SecurityContext.getAuthentication());
+        assertEquals(remembered,
+            SecurityContextHolder.getContext().getAuthentication());
     }
 
     protected void setUp() throws Exception {
         super.setUp();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     protected void tearDown() throws Exception {
         super.tearDown();
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     private void executeFilterInContainerSimulator(FilterConfig filterConfig,

+ 10 - 8
core/src/test/java/org/acegisecurity/ui/x509/X509ProcessingFilterTests.java

@@ -21,7 +21,7 @@ import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationManager;
 import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.MockAuthenticationManager;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.x509.X509AuthenticationToken;
 import net.sf.acegisecurity.providers.x509.X509TestUtils;
 import net.sf.acegisecurity.ui.AbstractProcessingFilter;
@@ -60,7 +60,7 @@ public class X509ProcessingFilterTests extends TestCase {
     }
 
     public void tearDown() {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testAuthenticationIsNullWithNoCertificate()
@@ -74,13 +74,13 @@ public class X509ProcessingFilterTests extends TestCase {
 
         filter.setAuthenticationManager(authMgr);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
         filter.doFilter(request, response, chain);
 
         Object lastException = request.getSession().getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY);
 
         assertNull("Authentication should be null",
-            SecurityContext.getAuthentication());
+            SecurityContextHolder.getContext().getAuthentication());
         assertTrue("BadCredentialsException should have been thrown",
             lastException instanceof BadCredentialsException);
     }
@@ -123,7 +123,7 @@ public class X509ProcessingFilterTests extends TestCase {
 
         AuthenticationManager authMgr = new MockAuthenticationManager(false);
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         X509ProcessingFilter filter = new X509ProcessingFilter();
 
@@ -133,7 +133,8 @@ public class X509ProcessingFilterTests extends TestCase {
         filter.doFilter(request, response, chain);
         filter.destroy();
 
-        Authentication result = SecurityContext.getAuthentication();
+        Authentication result = SecurityContextHolder.getContext()
+                                                     .getAuthentication();
 
         assertNull(result);
     }
@@ -159,7 +160,7 @@ public class X509ProcessingFilterTests extends TestCase {
 
         AuthenticationManager authMgr = new MockX509AuthenticationManager();
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         X509ProcessingFilter filter = new X509ProcessingFilter();
 
@@ -169,7 +170,8 @@ public class X509ProcessingFilterTests extends TestCase {
         filter.doFilter(request, response, chain);
         filter.destroy();
 
-        Authentication result = SecurityContext.getAuthentication();
+        Authentication result = SecurityContextHolder.getContext()
+                                                     .getAuthentication();
 
         assertNotNull(result);
     }

+ 9 - 9
core/src/test/java/org/acegisecurity/wrapper/ContextHolderAwareRequestWrapperTests.java

@@ -20,7 +20,7 @@ import junit.framework.TestCase;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.wrapper.ContextHolderAwareRequestWrapper;
@@ -60,7 +60,7 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase {
         Authentication auth = new TestingAuthenticationToken("marissa",
                 "koala",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_FOO")});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         MockHttpServletRequest request = new MockHttpServletRequest();
         request.setRequestURI("/");
@@ -72,7 +72,7 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase {
         assertFalse(wrapper.isUserInRole("ROLE_NOT_GRANTED"));
         assertEquals(auth, wrapper.getUserPrincipal());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testCorrectOperationWithUserDetailsBasedPrincipal()
@@ -82,7 +82,7 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase {
                     new GrantedAuthority[] {}), "koala",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_HELLO"), new GrantedAuthorityImpl(
                         "ROLE_FOOBAR")});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         MockHttpServletRequest request = new MockHttpServletRequest();
         request.setRequestURI("/");
@@ -96,11 +96,11 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase {
         assertTrue(wrapper.isUserInRole("ROLE_HELLO"));
         assertEquals(auth, wrapper.getUserPrincipal());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testNullAuthenticationHandling() throws Exception {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
 
         MockHttpServletRequest request = new MockHttpServletRequest();
         request.setRequestURI("/");
@@ -110,14 +110,14 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase {
         assertFalse(wrapper.isUserInRole("ROLE_ANY"));
         assertNull(wrapper.getUserPrincipal());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 
     public void testNullPrincipalHandling() throws Exception {
         Authentication auth = new TestingAuthenticationToken(null, "koala",
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_HELLO"), new GrantedAuthorityImpl(
                         "ROLE_FOOBAR")});
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
 
         MockHttpServletRequest request = new MockHttpServletRequest();
         request.setRequestURI("/");
@@ -129,6 +129,6 @@ public class ContextHolderAwareRequestWrapperTests extends TestCase {
         assertFalse(wrapper.isUserInRole("ROLE_FOOBAR")); // principal is null, so reject
         assertNull(wrapper.getUserPrincipal());
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.getContext().setAuthentication(null);
     }
 }

+ 1 - 1
doc/xdocs/changes.xml

@@ -26,7 +26,7 @@
   </properties>
   <body>
     <release version="0.9.0" date="In CVS">
-      <action dev="benalex" type="update">ContextHolder and related classes removed and replaced with SecurityContext</action>        
+      <action dev="benalex" type="update">ContextHolder refactored and replaced by SecurityContextHolder</action>        
       <action dev="luke_t" type="update">Changed order of credentials verification and expiry checking in DaoAuthenticationProvider. Password must now be successfully verified before expired credentials are reported. </action>        
       <action dev="benalex" type="update">AnonymousProcessingFilter offers protected method to control when it should execute</action>
       <action dev="benalex" type="fix">AbstractAuthenticationToken.getName() now returns username alone if UserDetails present</action>

+ 9 - 9
doc/xdocs/upgrade/upgrade-080-090.html

@@ -18,21 +18,21 @@ applications:
     <code>ContextHolder</code> allowed. <b>This is an important change in 0.9.0.</b> Many applications
     will need to modify their code (and possibly web views) if they directly interact with the old 
     <code>ContextHolder</code>. The replacement security <code>ThreadLocal</code> is called
-    <a href="../multiproject/acegi-security/xref/net/sf/acegisecurity/context/SecurityContext.html">
-    SecurityContext</a> and provides a single getter/setter for <code>Authentication</code>. There is
-    thus no need to work with <code>SecureContext</code> or <code>Context</code> anymore. <BR><BR>
+    <a href="../multiproject/acegi-security/xref/net/sf/acegisecurity/context/SecurityContextHolder.html">
+    SecurityContextHolder</a> and provides a single getter/setter for a
+    <a href="../multiproject/acegi-security/xref/net/sf/acegisecurity/context/SecurityContextHolder.html">SecurityContext</a>.
+    <code>SecurityContextHolder</code> guarantees to never return a <cod>null</code> <code>SecurityContext</code>.
+    <code>SecurityContext</code> provides single getter/setter for <code>Authentication</code>.<BR><BR>
     
     To migrate, simply modify all your code that previously worked with <code>ContextHolder</code>,
-    <code>SecureContext</code> and <code>Context</code> to directly call <code>SecurityContext</code>.
-    You will also note that the <code>HttpSessionContextIntegrationFilter</code> no longer provides
-    a <code>context</code> property, so remove it from your application context XML. For the relatively 
-    small number of users who had customised their context, you will need to write your own 
-    <code>ThreadLocal</code> to provide functionality for your specific use case.<BR><BR>    
+    <code>SecureContext</code> and <code>Context</code> to directly call <code>SecurityContextHolder</code>
+    and work with the <code>SecurityContext</code> (instead of the now removed <code>Context</code>
+    and <code>SecureContext</code> interfaces).<br><br>
     
     We apologise for the inconvenience, but on a more positive note this means you receive strict
     type checking, you no longer need to mess around with casting to and from <code>Context</code>
     implementations, your applications no longer need to perform checking of <code>null</code> and
-    unexpected <code>Context</code> implementation types, and the new <code>SecurityContext</code>
+    unexpected <code>Context</code> implementation types, and the new <code>SecurityContextHolder</code>
     is an <code>InheritableThreadLocal</code> - which should make life easier in rich client 
     environments.<br><br></li>
 

+ 4 - 3
samples/attributes/src/main/java/sample/attributes/Main.java

@@ -18,7 +18,8 @@ package sample.attributes;
 import net.sf.acegisecurity.AccessDeniedException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -66,10 +67,10 @@ public class Main {
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TELLER"), new GrantedAuthorityImpl(
                         "ROLE_PERMISSION_LIST")});
 
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
     }
 
     private static void destroySecureContext() {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 }

+ 4 - 3
samples/attributes/src/test/java/sample/attributes/BankTests.java

@@ -20,7 +20,8 @@ import junit.framework.TestCase;
 import net.sf.acegisecurity.AccessDeniedException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 
 import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -85,10 +86,10 @@ public class BankTests extends TestCase {
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_TELLER"), new GrantedAuthorityImpl(
                         "ROLE_PERMISSION_LIST")});
 
-        SecurityContext.setAuthentication(auth);
+        SecurityContextHolder.getContext().setAuthentication(auth);
     }
 
     private static void destroySecureContext() {
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 }

+ 4 - 3
samples/contacts/src/main/java/sample/contact/ClientApplication.java

@@ -16,7 +16,8 @@
 package sample.contact;
 
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+import net.sf.acegisecurity.context.SecurityContextImpl;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
 import org.springframework.beans.factory.ListableBeanFactory;
@@ -62,7 +63,7 @@ public class ClientApplication {
         Map contactServices = this.beanFactory.getBeansOfType(ContactManager.class,
                 true, true);
 
-        SecurityContext.setAuthentication(authentication);
+        SecurityContextHolder.getContext().setAuthentication(authentication);
 
         for (Iterator it = contactServices.keySet().iterator(); it.hasNext();) {
             String beanName = (String) it.next();
@@ -136,7 +137,7 @@ public class ClientApplication {
             System.out.println(stopWatch.prettyPrint());
         }
 
-        SecurityContext.setAuthentication(null);
+        SecurityContextHolder.setContext(new SecurityContextImpl());
     }
 
     public static void main(String[] args) {

+ 3 - 2
samples/contacts/src/main/java/sample/contact/ContactManagerBackend.java

@@ -21,7 +21,7 @@ import net.sf.acegisecurity.acl.basic.AclObjectIdentity;
 import net.sf.acegisecurity.acl.basic.BasicAclExtendedDao;
 import net.sf.acegisecurity.acl.basic.NamedEntityObjectIdentity;
 import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
-import net.sf.acegisecurity.context.SecurityContext;
+import net.sf.acegisecurity.context.SecurityContextHolder;
 
 import org.springframework.beans.factory.InitializingBean;
 
@@ -173,7 +173,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport
     }
 
     protected String getUsername() {
-        Authentication auth = SecurityContext.getAuthentication();
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
 
         if (auth.getPrincipal() instanceof UserDetails) {
             return ((UserDetails) auth.getPrincipal()).getUsername();

+ 2 - 2
samples/contacts/src/main/webapp/common/secure/debug.jsp

@@ -1,10 +1,10 @@
-<%@ page import="net.sf.acegisecurity.context.SecurityContext" %>
+<%@ page import="net.sf.acegisecurity.context.SecurityContextHolder" %>
 <%@ page import="net.sf.acegisecurity.Authentication" %>
 <%@ page import="net.sf.acegisecurity.GrantedAuthority" %>
 <%@ page import="net.sf.acegisecurity.adapters.AuthByAdapter" %>
 
 <% 
-		Authentication auth = SecurityContext.getAuthentication();
+		Authentication auth = SecurityContextHolder.getAuthentication();
 		if (auth != null) { %>
 			Authentication object is of type: <%= auth.getClass().getName() %><BR><BR>
 			Authentication object as a String: <%= auth.toString() %><BR><BR>