Browse Source

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

pull/1/head
Luke Taylor 15 years ago
parent
commit
5fce0a58bd
  1. 18
      core/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java
  2. 17
      core/src/main/java/org/springframework/security/access/intercept/InterceptorStatusToken.java
  3. 13
      core/src/test/java/org/springframework/security/access/intercept/InterceptorStatusTokenTests.java
  4. 15
      core/src/test/java/org/springframework/security/access/intercept/aopalliance/MethodSecurityInterceptorTests.java

18
core/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java

@ -40,6 +40,7 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF @@ -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 @@ -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 @@ -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;

17
core/src/main/java/org/springframework/security/access/intercept/InterceptorStatusToken.java

@ -19,6 +19,7 @@ import java.util.Collection; @@ -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; @@ -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 { @@ -54,8 +55,8 @@ public class InterceptorStatusToken {
return attr;
}
public Authentication getAuthentication() {
return authentication;
public SecurityContext getSecurityContext() {
return securityContext;
}
public Object getSecureObject() {

13
core/src/test/java/org/springframework/security/access/intercept/InterceptorStatusTokenTests.java

@ -15,8 +15,7 @@ @@ -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; @@ -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 { @@ -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());
}
}

15
core/src/test/java/org/springframework/security/access/intercept/aopalliance/MethodSecurityInterceptorTests.java

@ -19,12 +19,8 @@ import static org.junit.Assert.*; @@ -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; @@ -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 { @@ -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 { @@ -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)

Loading…
Cancel
Save