Kaynağa Gözat

SEC-1750: Make sure RunAs replacement is constrained to the SecurityContext of the current thread.

Luke Taylor 14 yıl önce
ebeveyn
işleme
5fce0a58bd

+ 11 - 7
core/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java

@@ -40,6 +40,7 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.SpringSecurityMessageSource;
+import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.util.Assert;
 
@@ -226,16 +227,18 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
             }
 
             // no further work post-invocation
-            return new InterceptorStatusToken(authenticated, false, attributes, object);
+            return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);
         } else {
             if (debug) {
                 logger.debug("Switching to RunAs Authentication: " + runAs);
             }
 
+            SecurityContext origCtx = SecurityContextHolder.getContext();
+            SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
             SecurityContextHolder.getContext().setAuthentication(runAs);
 
             // need to revert to token.Authenticated post-invocation
-            return new InterceptorStatusToken(authenticated, true, attributes, object);
+            return new InterceptorStatusToken(origCtx, true, attributes, object);
         }
     }
 
@@ -255,21 +258,22 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
 
         if (token.isContextHolderRefreshRequired()) {
             if (logger.isDebugEnabled()) {
-                logger.debug("Reverting to original Authentication: " + token.getAuthentication().toString());
+                logger.debug("Reverting to original Authentication: " + token.getSecurityContext().getAuthentication());
             }
 
-            SecurityContextHolder.getContext().setAuthentication(token.getAuthentication());
+            SecurityContextHolder.setContext(token.getSecurityContext());
         }
 
         if (afterInvocationManager != null) {
             // Attempt after invocation handling
             try {
-                returnedObject = afterInvocationManager.decide(token.getAuthentication(), token.getSecureObject(),
+                returnedObject = afterInvocationManager.decide(token.getSecurityContext().getAuthentication(),
+                        token.getSecureObject(),
                         token.getAttributes(), returnedObject);
             }
             catch (AccessDeniedException accessDeniedException) {
-                AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(),
-                        token.getAttributes(), token.getAuthentication(), accessDeniedException);
+                AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
+                        .getAttributes(), token.getSecurityContext().getAuthentication(), accessDeniedException);
                 publishEvent(event);
 
                 throw accessDeniedException;

+ 9 - 8
core/src/main/java/org/springframework/security/access/intercept/InterceptorStatusToken.java

@@ -19,6 +19,7 @@ import java.util.Collection;
 
 import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
 
 
 /**
@@ -33,16 +34,16 @@ import org.springframework.security.core.Authentication;
 public class InterceptorStatusToken {
     //~ Instance fields ================================================================================================
 
-    private final Authentication authentication;
-    private final Collection<ConfigAttribute> attr;
-    private final Object secureObject;
-    private final boolean contextHolderRefreshRequired;
+    private SecurityContext securityContext;
+    private Collection<ConfigAttribute> attr;
+    private Object secureObject;
+    private boolean contextHolderRefreshRequired;
 
     //~ Constructors ===================================================================================================
 
-    public InterceptorStatusToken(Authentication authentication, boolean contextHolderRefreshRequired,
+    public InterceptorStatusToken(SecurityContext securityContext, boolean contextHolderRefreshRequired,
             Collection<ConfigAttribute> attributes, Object secureObject) {
-        this.authentication = authentication;
+        this.securityContext = securityContext;
         this.contextHolderRefreshRequired = contextHolderRefreshRequired;
         this.attr = attributes;
         this.secureObject = secureObject;
@@ -54,8 +55,8 @@ public class InterceptorStatusToken {
         return attr;
     }
 
-    public Authentication getAuthentication() {
-        return authentication;
+    public SecurityContext getSecurityContext() {
+        return securityContext;
     }
 
     public Object getSecureObject() {

+ 6 - 7
core/src/test/java/org/springframework/security/access/intercept/InterceptorStatusTokenTests.java

@@ -15,8 +15,7 @@
 
 package org.springframework.security.access.intercept;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 import java.util.List;
 
@@ -24,8 +23,8 @@ import org.aopalliance.intercept.MethodInvocation;
 import org.junit.Test;
 import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.access.SecurityConfig;
-import org.springframework.security.access.intercept.InterceptorStatusToken;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.util.SimpleMethodInvocation;
 
 
@@ -40,12 +39,12 @@ public class InterceptorStatusTokenTests {
     public void testOperation() {
         List<ConfigAttribute> attr = SecurityConfig.createList("FOO");
         MethodInvocation mi = new SimpleMethodInvocation();
-        InterceptorStatusToken token = new InterceptorStatusToken(new UsernamePasswordAuthenticationToken("rod",
-                    "koala"), true, attr, mi);
+        SecurityContext ctx = SecurityContextHolder.createEmptyContext();
+        InterceptorStatusToken token = new InterceptorStatusToken(ctx, true, attr, mi);
 
         assertTrue(token.isContextHolderRefreshRequired());
         assertEquals(attr, token.getAttributes());
         assertEquals(mi, token.getSecureObject());
-        assertEquals("rod", token.getAuthentication().getPrincipal());
+        assertSame(ctx, token.getSecurityContext());
     }
 }

+ 8 - 7
core/src/test/java/org/springframework/security/access/intercept/aopalliance/MethodSecurityInterceptorTests.java

@@ -19,12 +19,8 @@ import static org.junit.Assert.*;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.*;
 
-import java.util.*;
-
 import org.aopalliance.intercept.MethodInvocation;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.*;
 import org.springframework.aop.framework.ProxyFactory;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.security.ITargetObject;
@@ -45,8 +41,11 @@ import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 
+import java.util.*;
+
 /**
  * Tests {@link MethodSecurityInterceptor}.
  *
@@ -251,7 +250,8 @@ public class MethodSecurityInterceptorTests {
 
     @Test
     public void runAsReplacementIsCorrectlySet() throws Exception {
-        SecurityContextHolder.getContext().setAuthentication(token);
+        SecurityContext ctx = SecurityContextHolder.getContext();
+        ctx.setAuthentication(token);
         token.setAuthenticated(true);
         final RunAsManager runAs = mock(RunAsManager.class);
         final RunAsUserToken runAsToken =
@@ -263,7 +263,8 @@ public class MethodSecurityInterceptorTests {
         String result = advisedTarget.makeUpperCase("hello");
         assertEquals("HELLO org.springframework.security.access.intercept.RunAsUserToken true", result);
         // Check we've changed back
-        assertEquals(token, SecurityContextHolder.getContext().getAuthentication());
+        assertSame(ctx, SecurityContextHolder.getContext());
+        assertSame(token, SecurityContextHolder.getContext().getAuthentication());
     }
 
     @Test(expected=AuthenticationCredentialsNotFoundException.class)