Add SecurityContextHolderStrategy to Method Security

Issue gh-11060
This commit is contained in:
Josh Cummings 2022-06-21 16:29:42 -06:00
parent 6ac9366657
commit 7a9c873d7d
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
8 changed files with 206 additions and 45 deletions

View File

@ -37,6 +37,7 @@ import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -50,14 +51,8 @@ import org.springframework.util.Assert;
public final class AuthorizationManagerAfterMethodInterceptor public final class AuthorizationManagerAfterMethodInterceptor
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
static final Supplier<Authentication> AUTHENTICATION_SUPPLIER = () -> { private Supplier<Authentication> authentication = getAuthentication(
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); SecurityContextHolder.getContextHolderStrategy());
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
private final Log logger = LogFactory.getLog(this.getClass()); private final Log logger = LogFactory.getLog(this.getClass());
@ -154,11 +149,21 @@ public final class AuthorizationManagerAfterMethodInterceptor
return true; return true;
} }
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
*
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
this.authentication = getAuthentication(strategy);
}
private void attemptAuthorization(MethodInvocation mi, Object result) { private void attemptAuthorization(MethodInvocation mi, Object result) {
this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi)); this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
MethodInvocationResult object = new MethodInvocationResult(mi, result); MethodInvocationResult object = new MethodInvocationResult(mi, result);
AuthorizationDecision decision = this.authorizationManager.check(AUTHENTICATION_SUPPLIER, object); AuthorizationDecision decision = this.authorizationManager.check(this.authentication, object);
this.eventPublisher.publishAuthorizationEvent(AUTHENTICATION_SUPPLIER, object, decision); this.eventPublisher.publishAuthorizationEvent(this.authentication, object, decision);
if (decision != null && !decision.isGranted()) { if (decision != null && !decision.isGranted()) {
this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager " this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
+ this.authorizationManager + " and decision " + decision)); + this.authorizationManager + " and decision " + decision));
@ -167,6 +172,17 @@ public final class AuthorizationManagerAfterMethodInterceptor
this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi)); this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
} }
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
return () -> {
Authentication authentication = strategy.getContext().getAuthentication();
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
}
private static <T> void noPublish(Supplier<Authentication> authentication, T object, private static <T> void noPublish(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision) { AuthorizationDecision decision) {

View File

@ -41,6 +41,7 @@ import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -54,14 +55,8 @@ import org.springframework.util.Assert;
public final class AuthorizationManagerBeforeMethodInterceptor public final class AuthorizationManagerBeforeMethodInterceptor
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
static final Supplier<Authentication> AUTHENTICATION_SUPPLIER = () -> { private Supplier<Authentication> authentication = getAuthentication(
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); SecurityContextHolder.getContextHolderStrategy());
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
private final Log logger = LogFactory.getLog(this.getClass()); private final Log logger = LogFactory.getLog(this.getClass());
@ -199,10 +194,20 @@ public final class AuthorizationManagerBeforeMethodInterceptor
return true; return true;
} }
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
*
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.authentication = getAuthentication(securityContextHolderStrategy);
}
private void attemptAuthorization(MethodInvocation mi) { private void attemptAuthorization(MethodInvocation mi) {
this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi)); this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
AuthorizationDecision decision = this.authorizationManager.check(AUTHENTICATION_SUPPLIER, mi); AuthorizationDecision decision = this.authorizationManager.check(this.authentication, mi);
this.eventPublisher.publishAuthorizationEvent(AUTHENTICATION_SUPPLIER, mi, decision); this.eventPublisher.publishAuthorizationEvent(this.authentication, mi, decision);
if (decision != null && !decision.isGranted()) { if (decision != null && !decision.isGranted()) {
this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager " this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
+ this.authorizationManager + " and decision " + decision)); + this.authorizationManager + " and decision " + decision));
@ -211,6 +216,17 @@ public final class AuthorizationManagerBeforeMethodInterceptor
this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi)); this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
} }
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
return () -> {
Authentication authentication = strategy.getContext().getAuthentication();
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
}
private static <T> void noPublish(Supplier<Authentication> authentication, T object, private static <T> void noPublish(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision) { AuthorizationDecision decision) {

View File

@ -37,6 +37,7 @@ import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -51,14 +52,8 @@ import org.springframework.util.Assert;
public final class PostFilterAuthorizationMethodInterceptor public final class PostFilterAuthorizationMethodInterceptor
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
private static final Supplier<Authentication> AUTHENTICATION_SUPPLIER = () -> { private Supplier<Authentication> authentication = getAuthentication(
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); SecurityContextHolder.getContextHolderStrategy());
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry(); private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry();
@ -115,6 +110,16 @@ public final class PostFilterAuthorizationMethodInterceptor
return true; return true;
} }
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
*
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
this.authentication = getAuthentication(strategy);
}
/** /**
* Filter a {@code returnedObject} using the {@link PostFilter} annotation that the * Filter a {@code returnedObject} using the {@link PostFilter} annotation that the
* {@link MethodInvocation} specifies. * {@link MethodInvocation} specifies.
@ -128,10 +133,21 @@ public final class PostFilterAuthorizationMethodInterceptor
if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) { if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
return returnedObject; return returnedObject;
} }
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(AUTHENTICATION_SUPPLIER, mi); EvaluationContext ctx = this.expressionHandler.createEvaluationContext(this.authentication, mi);
return this.expressionHandler.filter(returnedObject, attribute.getExpression(), ctx); return this.expressionHandler.filter(returnedObject, attribute.getExpression(), ctx);
} }
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
return () -> {
Authentication authentication = strategy.getContext().getAuthentication();
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
}
private final class PostFilterExpressionAttributeRegistry private final class PostFilterExpressionAttributeRegistry
extends AbstractExpressionAttributeRegistry<ExpressionAttribute> { extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {

View File

@ -37,6 +37,7 @@ import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -51,14 +52,8 @@ import org.springframework.util.StringUtils;
public final class PreFilterAuthorizationMethodInterceptor public final class PreFilterAuthorizationMethodInterceptor
implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean { implements Ordered, MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
private static final Supplier<Authentication> AUTHENTICATION_SUPPLIER = () -> { private Supplier<Authentication> authentication = getAuthentication(
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); SecurityContextHolder.getContextHolderStrategy());
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry(); private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry();
@ -115,6 +110,16 @@ public final class PreFilterAuthorizationMethodInterceptor
return true; return true;
} }
/**
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
*
* @since 5.8
*/
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy strategy) {
this.authentication = getAuthentication(strategy);
}
/** /**
* Filter the method argument specified in the {@link PreFilter} annotation that * Filter the method argument specified in the {@link PreFilter} annotation that
* {@link MethodInvocation} specifies. * {@link MethodInvocation} specifies.
@ -126,7 +131,7 @@ public final class PreFilterAuthorizationMethodInterceptor
if (attribute == PreFilterExpressionAttribute.NULL_ATTRIBUTE) { if (attribute == PreFilterExpressionAttribute.NULL_ATTRIBUTE) {
return mi.proceed(); return mi.proceed();
} }
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(AUTHENTICATION_SUPPLIER, mi); EvaluationContext ctx = this.expressionHandler.createEvaluationContext(this.authentication, mi);
Object filterTarget = findFilterTarget(attribute.filterTarget, ctx, mi); Object filterTarget = findFilterTarget(attribute.filterTarget, ctx, mi);
this.expressionHandler.filter(filterTarget, attribute.getExpression(), ctx); this.expressionHandler.filter(filterTarget, attribute.getExpression(), ctx);
return mi.proceed(); return mi.proceed();
@ -152,6 +157,17 @@ public final class PreFilterAuthorizationMethodInterceptor
return filterTarget; return filterTarget;
} }
private Supplier<Authentication> getAuthentication(SecurityContextHolderStrategy strategy) {
return () -> {
Authentication authentication = strategy.getContext().getAuthentication();
if (authentication == null) {
throw new AuthenticationCredentialsNotFoundException(
"An Authentication object was not found in the SecurityContext");
}
return authentication;
};
}
private final class PreFilterExpressionAttributeRegistry private final class PreFilterExpressionAttributeRegistry
extends AbstractExpressionAttributeRegistry<PreFilterExpressionAttribute> { extends AbstractExpressionAttributeRegistry<PreFilterExpressionAttribute> {

View File

@ -22,19 +22,21 @@ import org.aopalliance.intercept.MethodInvocation;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.aop.Pointcut; import org.springframework.aop.Pointcut;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager; import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.core.context.SecurityContextImpl;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -71,8 +73,22 @@ public class AuthorizationManagerAfterMethodInterceptorTests {
Pointcut.TRUE, mockAuthorizationManager); Pointcut.TRUE, mockAuthorizationManager);
Object returnedObject = advice.invoke(mockMethodInvocation); Object returnedObject = advice.invoke(mockMethodInvocation);
assertThat(returnedObject).isEqualTo(result.getResult()); assertThat(returnedObject).isEqualTo(result.getResult());
verify(mockAuthorizationManager).check(eq(AuthorizationManagerAfterMethodInterceptor.AUTHENTICATION_SUPPLIER), verify(mockAuthorizationManager).check(any(Supplier.class), any(MethodInvocationResult.class));
any(MethodInvocationResult.class)); }
@Test
public void afterWhenMockSecurityContextHolderStrategyThenUses() throws Throwable {
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
Authentication authentication = TestAuthentication.authenticatedUser();
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
MethodInvocation invocation = mock(MethodInvocation.class);
AuthorizationManager<MethodInvocationResult> authorizationManager = AuthenticatedAuthorizationManager
.authenticated();
AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
Pointcut.TRUE, authorizationManager);
advice.setSecurityContextHolderStrategy(strategy);
advice.invoke(invocation);
verify(strategy).getContext();
} }
@Test @Test

View File

@ -27,12 +27,16 @@ import org.springframework.security.authorization.AuthenticatedAuthorizationMana
import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.core.context.SecurityContextImpl;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -66,8 +70,22 @@ public class AuthorizationManagerBeforeMethodInterceptorTests {
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor( AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
Pointcut.TRUE, mockAuthorizationManager); Pointcut.TRUE, mockAuthorizationManager);
advice.invoke(mockMethodInvocation); advice.invoke(mockMethodInvocation);
verify(mockAuthorizationManager).check(AuthorizationManagerBeforeMethodInterceptor.AUTHENTICATION_SUPPLIER, verify(mockAuthorizationManager).check(any(Supplier.class), eq(mockMethodInvocation));
mockMethodInvocation); }
@Test
public void beforeWhenMockSecurityContextHolderStrategyThenUses() throws Throwable {
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
Authentication authentication = new TestingAuthenticationToken("user", "password",
AuthorityUtils.createAuthorityList("authority"));
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
MethodInvocation invocation = mock(MethodInvocation.class);
AuthorizationManager<MethodInvocation> authorizationManager = AuthenticatedAuthorizationManager.authenticated();
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
Pointcut.TRUE, authorizationManager);
advice.setSecurityContextHolderStrategy(strategy);
advice.invoke(invocation);
verify(strategy).getContext();
} }
@Test @Test

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,11 +31,19 @@ import org.springframework.security.access.expression.method.MethodSecurityExpre
import org.springframework.security.access.intercept.method.MockMethodInvocation; import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.authentication.TestAuthentication; import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/** /**
* Tests for {@link PostFilterAuthorizationMethodInterceptor}. * Tests for {@link PostFilterAuthorizationMethodInterceptor}.
@ -119,6 +127,26 @@ public class PostFilterAuthorizationMethodInterceptorTests {
.isThrownBy(() -> advice.invoke(methodInvocation)); .isThrownBy(() -> advice.invoke(methodInvocation));
} }
@Test
public void postFilterWhenMockSecurityContextHolderStrategyThenUses() throws Throwable {
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
Authentication authentication = new TestingAuthenticationToken("john", "password",
AuthorityUtils.createAuthorityList("authority"));
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
String[] array = { "john", "bob" };
MockMethodInvocation invocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingArrayAuthentication", new Class[] { String[].class }, new Object[] { array }) {
@Override
public Object proceed() {
return array;
}
};
PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
advice.setSecurityContextHolderStrategy(strategy);
advice.invoke(invocation);
verify(strategy).getContext();
}
@PostFilter("filterObject == 'john'") @PostFilter("filterObject == 'john'")
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo { public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
@ -131,6 +159,11 @@ public class PostFilterAuthorizationMethodInterceptorTests {
return array; return array;
} }
@PostFilter("filterObject == authentication.name")
public String[] doSomethingArrayAuthentication(String[] array) {
return array;
}
@Override @Override
public void inheritedAnnotations() { public void inheritedAnnotations() {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,12 +32,20 @@ import org.springframework.security.access.expression.method.MethodSecurityExpre
import org.springframework.security.access.intercept.method.MockMethodInvocation; import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.authentication.TestAuthentication; import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.context.SecurityContextImpl;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/** /**
* Tests for {@link PreFilterAuthorizationMethodInterceptor}. * Tests for {@link PreFilterAuthorizationMethodInterceptor}.
@ -178,6 +186,23 @@ public class PreFilterAuthorizationMethodInterceptorTests {
.isThrownBy(() -> advice.invoke(methodInvocation)); .isThrownBy(() -> advice.invoke(methodInvocation));
} }
@Test
public void preFilterWhenMockSecurityContextHolderStrategyThenUses() throws Throwable {
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
Authentication authentication = new TestingAuthenticationToken("john", "password",
AuthorityUtils.createAuthorityList("authority"));
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
List<String> list = new ArrayList<>();
list.add("john");
list.add("bob");
MockMethodInvocation invocation = new MockMethodInvocation(new TestClass(), TestClass.class,
"doSomethingArrayFilterAuthentication", new Class[] { List.class }, new Object[] { list });
PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
advice.setSecurityContextHolderStrategy(strategy);
advice.invoke(invocation);
verify(strategy).getContext();
}
@PreFilter("filterObject == 'john'") @PreFilter("filterObject == 'john'")
public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo { public static class TestClass implements InterfaceAnnotationsOne, InterfaceAnnotationsTwo {
@ -205,6 +230,11 @@ public class PreFilterAuthorizationMethodInterceptorTests {
return list; return list;
} }
@PreFilter(value = "filterObject == authentication.name", filterTarget = "list")
public List<String> doSomethingArrayFilterAuthentication(List<String> list) {
return list;
}
@Override @Override
public void inheritedAnnotations() { public void inheritedAnnotations() {