Bladeren bron

Use Interceptors instead of Advice

- Interceptor is a more descriptive term for what
method security is doing
- This also allows the code to follow a delegate
pattern that unifies both before-method and after-
method authorization

Issue gh-9289
Josh Cummings 4 jaren geleden
bovenliggende
commit
df8abcfae7
37 gewijzigde bestanden met toevoegingen van 1004 en 1238 verwijderingen
  1. 40 96
      config/src/main/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityConfiguration.java
  2. 51 13
      config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityConfigurationTests.java
  3. 11 0
      config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityService.java
  4. 7 0
      config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityServiceImpl.java
  5. 9 12
      core/src/main/java/org/springframework/security/authorization/method/AbstractAuthorizationManagerRegistry.java
  6. 7 11
      core/src/main/java/org/springframework/security/authorization/method/AbstractExpressionAttributeRegistry.java
  7. 16 15
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java
  8. 14 13
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java
  9. 0 70
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodAfterAdvice.java
  10. 0 62
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodBeforeAdvice.java
  11. 41 36
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodInterceptor.java
  12. 80 0
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodInterceptors.java
  13. 123 0
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodInvocation.java
  14. 54 0
      core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodPointcuts.java
  15. 0 106
      core/src/main/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodAfterAdvice.java
  16. 0 101
      core/src/main/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodBeforeAdvice.java
  17. 89 0
      core/src/main/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodInterceptor.java
  18. 10 11
      core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java
  19. 0 66
      core/src/main/java/org/springframework/security/authorization/method/MethodAuthorizationContext.java
  20. 11 13
      core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.java
  21. 15 22
      core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java
  22. 8 10
      core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.java
  23. 13 15
      core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java
  24. 9 11
      core/src/main/java/org/springframework/security/authorization/method/SecuredAuthorizationManager.java
  25. 10 8
      core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java
  26. 9 8
      core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java
  27. 167 0
      core/src/test/java/org/springframework/security/authorization/method/AuthorizationMethodPointcutsTests.java
  28. 0 165
      core/src/test/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodAfterAdviceTests.java
  29. 0 164
      core/src/test/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodBeforeAdviceTests.java
  30. 21 22
      core/src/test/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodInterceptorTests.java
  31. 25 29
      core/src/test/java/org/springframework/security/authorization/method/Jsr250AuthorizationManagerTests.java
  32. 15 20
      core/src/test/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManagerTests.java
  33. 28 26
      core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptorTests.java
  34. 11 12
      core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManagerTests.java
  35. 47 52
      core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptorTests.java
  36. 17 19
      core/src/test/java/org/springframework/security/authorization/method/SecuredAuthorizationManagerTests.java
  37. 46 30
      docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc

+ 40 - 96
config/src/main/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityConfiguration.java

@@ -16,20 +16,11 @@
 
 package org.springframework.security.config.annotation.method.configuration;
 
-import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import javax.annotation.security.DenyAll;
-import javax.annotation.security.PermitAll;
-import javax.annotation.security.RolesAllowed;
-
-import org.springframework.aop.Pointcut;
-import org.springframework.aop.support.ComposablePointcut;
 import org.springframework.aop.support.DefaultPointcutAdvisor;
-import org.springframework.aop.support.Pointcuts;
-import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.config.BeanDefinition;
@@ -39,26 +30,16 @@ import org.springframework.context.annotation.ImportAware;
 import org.springframework.context.annotation.Role;
 import org.springframework.core.annotation.AnnotationAttributes;
 import org.springframework.core.type.AnnotationMetadata;
-import org.springframework.security.access.annotation.Secured;
 import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
 import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
-import org.springframework.security.access.prepost.PostAuthorize;
-import org.springframework.security.access.prepost.PostFilter;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.access.prepost.PreFilter;
-import org.springframework.security.authorization.method.AuthorizationManagerMethodAfterAdvice;
-import org.springframework.security.authorization.method.AuthorizationManagerMethodBeforeAdvice;
-import org.springframework.security.authorization.method.AuthorizationMethodAfterAdvice;
-import org.springframework.security.authorization.method.AuthorizationMethodBeforeAdvice;
 import org.springframework.security.authorization.method.AuthorizationMethodInterceptor;
-import org.springframework.security.authorization.method.DelegatingAuthorizationMethodAfterAdvice;
-import org.springframework.security.authorization.method.DelegatingAuthorizationMethodBeforeAdvice;
+import org.springframework.security.authorization.method.AuthorizationMethodInterceptors;
+import org.springframework.security.authorization.method.DelegatingAuthorizationMethodInterceptor;
 import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
-import org.springframework.security.authorization.method.MethodAuthorizationContext;
 import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
-import org.springframework.security.authorization.method.PostFilterAuthorizationMethodAfterAdvice;
+import org.springframework.security.authorization.method.PostFilterAuthorizationMethodInterceptor;
 import org.springframework.security.authorization.method.PreAuthorizeAuthorizationManager;
-import org.springframework.security.authorization.method.PreFilterAuthorizationMethodBeforeAdvice;
+import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
 import org.springframework.security.authorization.method.SecuredAuthorizationManager;
 import org.springframework.security.config.core.GrantedAuthorityDefaults;
 import org.springframework.util.Assert;
@@ -79,30 +60,19 @@ final class MethodSecurityConfiguration implements ImportAware, InitializingBean
 
 	private GrantedAuthorityDefaults grantedAuthorityDefaults;
 
-	private AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> authorizationMethodBeforeAdvice;
-
-	private AuthorizationMethodAfterAdvice<MethodAuthorizationContext> authorizationMethodAfterAdvice;
+	private AuthorizationMethodInterceptor interceptor;
 
 	private AnnotationAttributes enableMethodSecurity;
 
 	@Bean
 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
-	DefaultPointcutAdvisor methodSecurityAdvisor(AuthorizationMethodInterceptor interceptor) {
-		AuthorizationMethodBeforeAdvice<?> beforeAdvice = getAuthorizationMethodBeforeAdvice();
-		AuthorizationMethodAfterAdvice<?> afterAdvice = getAuthorizationMethodAfterAdvice();
-		Pointcut pointcut = Pointcuts.union(beforeAdvice.getPointcut(), afterAdvice.getPointcut());
-		DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, interceptor);
+	DefaultPointcutAdvisor methodSecurityAdvisor() {
+		AuthorizationMethodInterceptor interceptor = getInterceptor();
+		DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(interceptor.getPointcut(), interceptor);
 		advisor.setOrder(order());
 		return advisor;
 	}
 
-	@Bean
-	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
-	AuthorizationMethodInterceptor authorizationMethodInterceptor() {
-		return new AuthorizationMethodInterceptor(getAuthorizationMethodBeforeAdvice(),
-				getAuthorizationMethodAfterAdvice());
-	}
-
 	private MethodSecurityExpressionHandler getMethodSecurityExpressionHandler() {
 		if (this.methodSecurityExpressionHandler == null) {
 			DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
@@ -124,15 +94,18 @@ final class MethodSecurityConfiguration implements ImportAware, InitializingBean
 		this.grantedAuthorityDefaults = grantedAuthorityDefaults;
 	}
 
-	private AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> getAuthorizationMethodBeforeAdvice() {
-		if (this.authorizationMethodBeforeAdvice == null) {
-			this.authorizationMethodBeforeAdvice = createDefaultAuthorizationMethodBeforeAdvice();
+	private AuthorizationMethodInterceptor getInterceptor() {
+		if (this.interceptor != null) {
+			return this.interceptor;
 		}
-		return this.authorizationMethodBeforeAdvice;
+		List<AuthorizationMethodInterceptor> interceptors = new ArrayList<>();
+		interceptors.addAll(createDefaultAuthorizationMethodBeforeAdvice());
+		interceptors.addAll(createDefaultAuthorizationMethodAfterAdvice());
+		return new DelegatingAuthorizationMethodInterceptor(interceptors);
 	}
 
-	private AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> createDefaultAuthorizationMethodBeforeAdvice() {
-		List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> beforeAdvices = new ArrayList<>();
+	private List<AuthorizationMethodInterceptor> createDefaultAuthorizationMethodBeforeAdvice() {
+		List<AuthorizationMethodInterceptor> beforeAdvices = new ArrayList<>();
 		beforeAdvices.add(getPreFilterAuthorizationMethodBeforeAdvice());
 		beforeAdvices.add(getPreAuthorizeAuthorizationMethodBeforeAdvice());
 		if (securedEnabled()) {
@@ -141,79 +114,55 @@ final class MethodSecurityConfiguration implements ImportAware, InitializingBean
 		if (jsr250Enabled()) {
 			beforeAdvices.add(getJsr250AuthorizationMethodBeforeAdvice());
 		}
-		return new DelegatingAuthorizationMethodBeforeAdvice<>(beforeAdvices);
+		return beforeAdvices;
 	}
 
-	private PreFilterAuthorizationMethodBeforeAdvice getPreFilterAuthorizationMethodBeforeAdvice() {
-		Pointcut pointcut = forAnnotation(PreFilter.class);
-		PreFilterAuthorizationMethodBeforeAdvice preFilterBeforeAdvice = new PreFilterAuthorizationMethodBeforeAdvice(
-				pointcut);
-		preFilterBeforeAdvice.setExpressionHandler(getMethodSecurityExpressionHandler());
-		return preFilterBeforeAdvice;
+	private PreFilterAuthorizationMethodInterceptor getPreFilterAuthorizationMethodBeforeAdvice() {
+		PreFilterAuthorizationMethodInterceptor interceptor = new PreFilterAuthorizationMethodInterceptor();
+		interceptor.setExpressionHandler(getMethodSecurityExpressionHandler());
+		return interceptor;
 	}
 
-	private AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> getPreAuthorizeAuthorizationMethodBeforeAdvice() {
-		Pointcut pointcut = forAnnotation(PreAuthorize.class);
+	private AuthorizationMethodInterceptor getPreAuthorizeAuthorizationMethodBeforeAdvice() {
 		PreAuthorizeAuthorizationManager authorizationManager = new PreAuthorizeAuthorizationManager();
 		authorizationManager.setExpressionHandler(getMethodSecurityExpressionHandler());
-		return new AuthorizationManagerMethodBeforeAdvice<>(pointcut, authorizationManager);
+		return AuthorizationMethodInterceptors.preAuthorize(authorizationManager);
 	}
 
-	private AuthorizationManagerMethodBeforeAdvice<MethodAuthorizationContext> getSecuredAuthorizationMethodBeforeAdvice() {
-		Pointcut pointcut = forAnnotation(Secured.class);
-		SecuredAuthorizationManager authorizationManager = new SecuredAuthorizationManager();
-		return new AuthorizationManagerMethodBeforeAdvice<>(pointcut, authorizationManager);
+	private AuthorizationMethodInterceptor getSecuredAuthorizationMethodBeforeAdvice() {
+		return AuthorizationMethodInterceptors.secured(new SecuredAuthorizationManager());
 	}
 
-	private AuthorizationManagerMethodBeforeAdvice<MethodAuthorizationContext> getJsr250AuthorizationMethodBeforeAdvice() {
-		Pointcut pointcut = new ComposablePointcut(forAnnotation(DenyAll.class)).union(forAnnotation(PermitAll.class))
-				.union(forAnnotation(RolesAllowed.class));
+	private AuthorizationMethodInterceptor getJsr250AuthorizationMethodBeforeAdvice() {
 		Jsr250AuthorizationManager authorizationManager = new Jsr250AuthorizationManager();
 		if (this.grantedAuthorityDefaults != null) {
 			authorizationManager.setRolePrefix(this.grantedAuthorityDefaults.getRolePrefix());
 		}
-		return new AuthorizationManagerMethodBeforeAdvice<>(pointcut, authorizationManager);
+		return AuthorizationMethodInterceptors.jsr250(authorizationManager);
 	}
 
 	@Autowired(required = false)
-	void setAuthorizationMethodBeforeAdvice(
-			AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> authorizationMethodBeforeAdvice) {
-		this.authorizationMethodBeforeAdvice = authorizationMethodBeforeAdvice;
-	}
-
-	private AuthorizationMethodAfterAdvice<MethodAuthorizationContext> getAuthorizationMethodAfterAdvice() {
-		if (this.authorizationMethodAfterAdvice == null) {
-			this.authorizationMethodAfterAdvice = createDefaultAuthorizationMethodAfterAdvice();
-		}
-		return this.authorizationMethodAfterAdvice;
+	void setAuthorizationMethodInterceptor(AuthorizationMethodInterceptor interceptor) {
+		this.interceptor = interceptor;
 	}
 
-	private AuthorizationMethodAfterAdvice<MethodAuthorizationContext> createDefaultAuthorizationMethodAfterAdvice() {
-		List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> afterAdvices = new ArrayList<>();
+	private List<AuthorizationMethodInterceptor> createDefaultAuthorizationMethodAfterAdvice() {
+		List<AuthorizationMethodInterceptor> afterAdvices = new ArrayList<>();
 		afterAdvices.add(getPostFilterAuthorizationMethodAfterAdvice());
 		afterAdvices.add(getPostAuthorizeAuthorizationMethodAfterAdvice());
-		return new DelegatingAuthorizationMethodAfterAdvice<>(afterAdvices);
+		return afterAdvices;
 	}
 
-	private PostFilterAuthorizationMethodAfterAdvice getPostFilterAuthorizationMethodAfterAdvice() {
-		Pointcut pointcut = forAnnotation(PostFilter.class);
-		PostFilterAuthorizationMethodAfterAdvice postFilterAfterAdvice = new PostFilterAuthorizationMethodAfterAdvice(
-				pointcut);
-		postFilterAfterAdvice.setExpressionHandler(getMethodSecurityExpressionHandler());
-		return postFilterAfterAdvice;
+	private AuthorizationMethodInterceptor getPostFilterAuthorizationMethodAfterAdvice() {
+		PostFilterAuthorizationMethodInterceptor interceptor = new PostFilterAuthorizationMethodInterceptor();
+		interceptor.setExpressionHandler(getMethodSecurityExpressionHandler());
+		return interceptor;
 	}
 
-	private AuthorizationManagerMethodAfterAdvice<MethodAuthorizationContext> getPostAuthorizeAuthorizationMethodAfterAdvice() {
-		Pointcut pointcut = forAnnotation(PostAuthorize.class);
+	private AuthorizationMethodInterceptor getPostAuthorizeAuthorizationMethodAfterAdvice() {
 		PostAuthorizeAuthorizationManager authorizationManager = new PostAuthorizeAuthorizationManager();
 		authorizationManager.setExpressionHandler(getMethodSecurityExpressionHandler());
-		return new AuthorizationManagerMethodAfterAdvice<>(pointcut, authorizationManager);
-	}
-
-	@Autowired(required = false)
-	void setAuthorizationMethodAfterAdvice(
-			AuthorizationMethodAfterAdvice<MethodAuthorizationContext> authorizationMethodAfterAdvice) {
-		this.authorizationMethodAfterAdvice = authorizationMethodAfterAdvice;
+		return AuthorizationMethodInterceptors.postAuthorize(authorizationManager);
 	}
 
 	@Override
@@ -227,7 +176,7 @@ final class MethodSecurityConfiguration implements ImportAware, InitializingBean
 		if (!securedEnabled() && !jsr250Enabled()) {
 			return;
 		}
-		Assert.isNull(this.authorizationMethodBeforeAdvice,
+		Assert.isNull(this.interceptor,
 				"You have specified your own advice, meaning that the annotation attributes securedEnabled and jsr250Enabled will be ignored. Please choose one or the other.");
 	}
 
@@ -243,9 +192,4 @@ final class MethodSecurityConfiguration implements ImportAware, InitializingBean
 		return this.enableMethodSecurity.getNumber("order");
 	}
 
-	private Pointcut forAnnotation(Class<? extends Annotation> annotationClass) {
-		return Pointcuts.union(new AnnotationMatchingPointcut(annotationClass, true),
-				new AnnotationMatchingPointcut(null, annotationClass, true));
-	}
-
 }

+ 51 - 13
config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityConfigurationTests.java

@@ -18,9 +18,11 @@ package org.springframework.security.config.annotation.method.configuration;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.function.Supplier;
 
+import org.aopalliance.intercept.MethodInvocation;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -38,10 +40,8 @@ import org.springframework.security.access.expression.method.DefaultMethodSecuri
 import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
 import org.springframework.security.authorization.AuthorizationDecision;
 import org.springframework.security.authorization.AuthorizationManager;
-import org.springframework.security.authorization.method.AuthorizationManagerMethodBeforeAdvice;
-import org.springframework.security.authorization.method.AuthorizationMethodAfterAdvice;
-import org.springframework.security.authorization.method.AuthorizationMethodBeforeAdvice;
-import org.springframework.security.authorization.method.MethodAuthorizationContext;
+import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
+import org.springframework.security.authorization.method.AuthorizationMethodInterceptor;
 import org.springframework.security.config.test.SpringTestRule;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
@@ -273,6 +273,43 @@ public class MethodSecurityConfigurationTests {
 		this.businessService.rolesAllowedUser();
 	}
 
+	@WithMockUser(roles = { "ADMIN", "USER" })
+	@Test
+	public void manyAnnotationsWhenMeetsConditionsThenReturnsFilteredList() throws Exception {
+		List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
+		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
+		List<String> filtered = this.methodSecurityService.manyAnnotations(new ArrayList<>(names));
+		assertThat(filtered).hasSize(2);
+		assertThat(filtered).containsExactly("harold", "jonathan");
+	}
+
+	@WithMockUser
+	@Test
+	public void manyAnnotationsWhenUserThenFails() {
+		List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
+		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
+		assertThatExceptionOfType(AccessDeniedException.class)
+				.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
+	}
+
+	@WithMockUser
+	@Test
+	public void manyAnnotationsWhenShortListThenFails() {
+		List<String> names = Arrays.asList("harold", "jonathan", "pete");
+		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
+		assertThatExceptionOfType(AccessDeniedException.class)
+				.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
+	}
+
+	@WithMockUser(roles = "ADMIN")
+	@Test
+	public void manyAnnotationsWhenAdminThenFails() {
+		List<String> names = Arrays.asList("harold", "jonathan", "pete", "bo");
+		this.spring.register(MethodSecurityServiceEnabledConfig.class).autowire();
+		assertThatExceptionOfType(AccessDeniedException.class)
+				.isThrownBy(() -> this.methodSecurityService.manyAnnotations(new ArrayList<>(names)));
+	}
+
 	@Test
 	public void configureWhenCustomAdviceAndSecureEnabledThenException() {
 		assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> this.spring
@@ -338,12 +375,12 @@ public class MethodSecurityConfigurationTests {
 	static class CustomAuthorizationManagerBeforeAdviceConfig {
 
 		@Bean
-		AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> customBeforeAdvice() {
-			JdkRegexpMethodPointcut methodMatcher = new JdkRegexpMethodPointcut();
-			methodMatcher.setPattern(".*MethodSecurityServiceImpl.*securedUser");
-			AuthorizationManager<MethodAuthorizationContext> authorizationManager = (a,
+		AuthorizationMethodInterceptor customBeforeAdvice() {
+			JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
+			pointcut.setPattern(".*MethodSecurityServiceImpl.*securedUser");
+			AuthorizationManager<MethodInvocation> authorizationManager = (a,
 					o) -> new AuthorizationDecision("bob".equals(a.get().getName()));
-			return new AuthorizationManagerMethodBeforeAdvice<>(methodMatcher, authorizationManager);
+			return new AuthorizationManagerBeforeMethodInterceptor(pointcut, authorizationManager);
 		}
 
 	}
@@ -352,18 +389,18 @@ public class MethodSecurityConfigurationTests {
 	static class CustomAuthorizationManagerAfterAdviceConfig {
 
 		@Bean
-		AuthorizationMethodAfterAdvice<MethodAuthorizationContext> customAfterAdvice() {
+
+		AuthorizationMethodInterceptor customAfterAdvice() {
 			JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
 			pointcut.setPattern(".*MethodSecurityServiceImpl.*securedUser");
-			return new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
+			AuthorizationMethodInterceptor interceptor = new AuthorizationMethodInterceptor() {
 				@Override
 				public Pointcut getPointcut() {
 					return pointcut;
 				}
 
 				@Override
-				public Object after(Supplier<Authentication> authentication,
-						MethodAuthorizationContext methodAuthorizationContext, Object returnedObject) {
+				public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) {
 					Authentication auth = authentication.get();
 					if ("bob".equals(auth.getName())) {
 						return "granted";
@@ -371,6 +408,7 @@ public class MethodSecurityConfigurationTests {
 					throw new AccessDeniedException("Access Denied for User '" + auth.getName() + "'");
 				}
 			};
+			return interceptor;
 		}
 
 	}

+ 11 - 0
config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityService.java

@@ -16,12 +16,16 @@
 
 package org.springframework.security.config.annotation.method.configuration;
 
+import java.util.List;
+
 import javax.annotation.security.DenyAll;
 import javax.annotation.security.PermitAll;
 
 import org.springframework.security.access.annotation.Secured;
 import org.springframework.security.access.prepost.PostAuthorize;
+import org.springframework.security.access.prepost.PostFilter;
 import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.access.prepost.PreFilter;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.parameters.P;
 
@@ -69,4 +73,11 @@ public interface MethodSecurityService {
 	@PostAuthorize("#o?.contains('grant')")
 	String postAnnotation(@P("o") String object);
 
+	@PreFilter("filterObject.length > 3")
+	@PreAuthorize("hasRole('ADMIN')")
+	@Secured("ROLE_USER")
+	@PostFilter("filterObject.length > 5")
+	@PostAuthorize("returnObject.size > 1")
+	List<String> manyAnnotations(List<String> array);
+
 }

+ 7 - 0
config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityServiceImpl.java

@@ -16,6 +16,8 @@
 
 package org.springframework.security.config.annotation.method.configuration;
 
+import java.util.List;
+
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 
@@ -86,4 +88,9 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
 		return null;
 	}
 
+	@Override
+	public List<String> manyAnnotations(List<String> object) {
+		return object;
+	}
+
 }

+ 9 - 12
core/src/main/java/org/springframework/security/authorization/method/AbstractAuthorizationManagerRegistry.java

@@ -27,28 +27,25 @@ import org.springframework.lang.NonNull;
 import org.springframework.security.authorization.AuthorizationManager;
 
 /**
- * An abstract registry which provides an {@link AuthorizationManager} for the
- * {@link MethodInvocation}.
+ * For internal use only, as this contract is likely to change
  *
  * @author Evgeniy Cheban
- * @since 5.5
  */
 abstract class AbstractAuthorizationManagerRegistry {
 
-	static final AuthorizationManager<MethodAuthorizationContext> NULL_MANAGER = (a, o) -> null;
+	static final AuthorizationManager<MethodInvocation> NULL_MANAGER = (a, o) -> null;
 
-	private final Map<MethodClassKey, AuthorizationManager<MethodAuthorizationContext>> cachedManagers = new ConcurrentHashMap<>();
+	private final Map<MethodClassKey, AuthorizationManager<MethodInvocation>> cachedManagers = new ConcurrentHashMap<>();
 
 	/**
-	 * Returns an {@link AuthorizationManager} for the {@link MethodAuthorizationContext}.
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to use
+	 * Returns an {@link AuthorizationManager} for the
+	 * {@link AuthorizationMethodInvocation}.
+	 * @param methodInvocation the {@link AuthorizationMethodInvocation} to use
 	 * @return an {@link AuthorizationManager} to use
 	 */
-	final AuthorizationManager<MethodAuthorizationContext> getManager(
-			MethodAuthorizationContext methodAuthorizationContext) {
-		MethodInvocation methodInvocation = methodAuthorizationContext.getMethodInvocation();
+	final AuthorizationManager<MethodInvocation> getManager(AuthorizationMethodInvocation methodInvocation) {
 		Method method = methodInvocation.getMethod();
-		Class<?> targetClass = methodAuthorizationContext.getTargetClass();
+		Class<?> targetClass = methodInvocation.getTargetClass();
 		MethodClassKey cacheKey = new MethodClassKey(method, targetClass);
 		return this.cachedManagers.computeIfAbsent(cacheKey, (k) -> resolveManager(method, targetClass));
 	}
@@ -61,6 +58,6 @@ abstract class AbstractAuthorizationManagerRegistry {
 	 * @return the non-null {@link AuthorizationManager}
 	 */
 	@NonNull
-	abstract AuthorizationManager<MethodAuthorizationContext> resolveManager(Method method, Class<?> targetClass);
+	abstract AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass);
 
 }

+ 7 - 11
core/src/main/java/org/springframework/security/authorization/method/AbstractExpressionAttributeRegistry.java

@@ -20,31 +20,27 @@ import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
-import org.aopalliance.intercept.MethodInvocation;
-
 import org.springframework.core.MethodClassKey;
 import org.springframework.lang.NonNull;
 
 /**
- * An abstract registry which provides an {@link ExpressionAttribute} for the
- * {@link MethodInvocation}.
+ * For internal use only, as this contract is likely to change
  *
  * @author Evgeniy Cheban
- * @since 5.5
  */
 abstract class AbstractExpressionAttributeRegistry<T extends ExpressionAttribute> {
 
 	private final Map<MethodClassKey, T> cachedAttributes = new ConcurrentHashMap<>();
 
 	/**
-	 * Returns an {@link ExpressionAttribute} for the {@link MethodAuthorizationContext}.
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to use
+	 * Returns an {@link ExpressionAttribute} for the
+	 * {@link AuthorizationMethodInvocation}.
+	 * @param mi the {@link AuthorizationMethodInvocation} to use
 	 * @return the {@link ExpressionAttribute} to use
 	 */
-	final T getAttribute(MethodAuthorizationContext methodAuthorizationContext) {
-		MethodInvocation methodInvocation = methodAuthorizationContext.getMethodInvocation();
-		Method method = methodInvocation.getMethod();
-		Class<?> targetClass = methodAuthorizationContext.getTargetClass();
+	final T getAttribute(AuthorizationMethodInvocation mi) {
+		Method method = mi.getMethod();
+		Class<?> targetClass = mi.getTargetClass();
 		return getAttribute(method, targetClass);
 	}
 

+ 16 - 15
core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerMethodAfterAdvice.java → core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java

@@ -18,7 +18,8 @@ package org.springframework.security.authorization.method;
 
 import java.util.function.Supplier;
 
-import org.springframework.aop.MethodMatcher;
+import org.aopalliance.intercept.MethodInvocation;
+
 import org.springframework.aop.Pointcut;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.authorization.AuthorizationManager;
@@ -26,28 +27,27 @@ import org.springframework.security.core.Authentication;
 import org.springframework.util.Assert;
 
 /**
- * An {@link AuthorizationMethodAfterAdvice} which can determine if an
- * {@link Authentication} has access to the {@link T} object using an
- * {@link AuthorizationManager} if a {@link MethodMatcher} matches.
+ * An {@link AuthorizationMethodInterceptor} which can determine if an
+ * {@link Authentication} has access to the result of an {@link MethodInvocation} using an
+ * {@link AuthorizationManager}
  *
- * @param <T> the type of object that the authorization check is being done one.
  * @author Evgeniy Cheban
  * @author Josh Cummings
  * @since 5.5
  */
-public final class AuthorizationManagerMethodAfterAdvice<T> implements AuthorizationMethodAfterAdvice<T> {
+public final class AuthorizationManagerAfterMethodInterceptor implements AuthorizationMethodInterceptor {
 
 	private final Pointcut pointcut;
 
-	private final AfterMethodAuthorizationManager<T> authorizationManager;
+	private final AfterMethodAuthorizationManager<MethodInvocation> authorizationManager;
 
 	/**
 	 * Creates an instance.
 	 * @param pointcut the {@link Pointcut} to use
 	 * @param authorizationManager the {@link AuthorizationManager} to use
 	 */
-	public AuthorizationManagerMethodAfterAdvice(Pointcut pointcut,
-			AfterMethodAuthorizationManager<T> authorizationManager) {
+	public AuthorizationManagerAfterMethodInterceptor(Pointcut pointcut,
+			AfterMethodAuthorizationManager<MethodInvocation> authorizationManager) {
 		Assert.notNull(pointcut, "pointcut cannot be null");
 		Assert.notNull(authorizationManager, "authorizationManager cannot be null");
 		this.pointcut = pointcut;
@@ -55,16 +55,17 @@ public final class AuthorizationManagerMethodAfterAdvice<T> implements Authoriza
 	}
 
 	/**
-	 * Determine if an {@link Authentication} has access to the {@link T} object using the
-	 * {@link AuthorizationManager}.
+	 * Determine if an {@link Authentication} has access to the {@link MethodInvocation}
+	 * using the {@link AuthorizationManager}.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param object the {@link T} object to check
+	 * @param mi the {@link MethodInvocation} to check
 	 * @throws AccessDeniedException if access is not granted
 	 */
 	@Override
-	public Object after(Supplier<Authentication> authentication, T context, Object object) {
-		this.authorizationManager.verify(authentication, context, object);
-		return object;
+	public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
+		Object result = mi.proceed();
+		this.authorizationManager.verify(authentication, mi, result);
+		return result;
 	}
 
 	/**

+ 14 - 13
core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerMethodBeforeAdvice.java → core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java

@@ -18,7 +18,8 @@ package org.springframework.security.authorization.method;
 
 import java.util.function.Supplier;
 
-import org.springframework.aop.MethodMatcher;
+import org.aopalliance.intercept.MethodInvocation;
+
 import org.springframework.aop.Pointcut;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.authorization.AuthorizationManager;
@@ -26,27 +27,26 @@ import org.springframework.security.core.Authentication;
 import org.springframework.util.Assert;
 
 /**
- * An {@link AuthorizationMethodBeforeAdvice} which can determine if an
- * {@link Authentication} has access to the {@link T} object using an
- * {@link AuthorizationManager} if a {@link MethodMatcher} matches.
+ * An {@link AuthorizationMethodInterceptor} which uses a {@link AuthorizationManager} to
+ * determine if an {@link Authentication} may invoke the given {@link MethodInvocation}
  *
- * @param <T> the type of object that the authorization check is being done one.
  * @author Evgeniy Cheban
  * @author Josh Cummings
  * @since 5.5
  */
-public final class AuthorizationManagerMethodBeforeAdvice<T> implements AuthorizationMethodBeforeAdvice<T> {
+public final class AuthorizationManagerBeforeMethodInterceptor implements AuthorizationMethodInterceptor {
 
 	private final Pointcut pointcut;
 
-	private final AuthorizationManager<T> authorizationManager;
+	private final AuthorizationManager<MethodInvocation> authorizationManager;
 
 	/**
 	 * Creates an instance.
 	 * @param pointcut the {@link Pointcut} to use
 	 * @param authorizationManager the {@link AuthorizationManager} to use
 	 */
-	public AuthorizationManagerMethodBeforeAdvice(Pointcut pointcut, AuthorizationManager<T> authorizationManager) {
+	public AuthorizationManagerBeforeMethodInterceptor(Pointcut pointcut,
+			AuthorizationManager<MethodInvocation> authorizationManager) {
 		Assert.notNull(pointcut, "pointcut cannot be null");
 		Assert.notNull(authorizationManager, "authorizationManager cannot be null");
 		this.pointcut = pointcut;
@@ -54,15 +54,16 @@ public final class AuthorizationManagerMethodBeforeAdvice<T> implements Authoriz
 	}
 
 	/**
-	 * Determine if an {@link Authentication} has access to the {@link T} object using the
-	 * configured {@link AuthorizationManager}.
+	 * Determine if an {@link Authentication} has access to the {@link MethodInvocation}
+	 * using the configured {@link AuthorizationManager}.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param object the {@link T} object to check
+	 * @param mi the {@link MethodInvocation} to check
 	 * @throws AccessDeniedException if access is not granted
 	 */
 	@Override
-	public void before(Supplier<Authentication> authentication, T object) {
-		this.authorizationManager.verify(authentication, object);
+	public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
+		this.authorizationManager.verify(authentication, mi);
+		return mi.proceed();
 	}
 
 	/**

+ 0 - 70
core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodAfterAdvice.java

@@ -1,70 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * 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
- *
- *      https://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 org.springframework.security.authorization.method;
-
-import java.util.function.Supplier;
-
-import org.aopalliance.aop.Advice;
-import org.aopalliance.intercept.MethodInvocation;
-
-import org.springframework.aop.AfterAdvice;
-import org.springframework.aop.PointcutAdvisor;
-import org.springframework.aop.framework.AopInfrastructureBean;
-import org.springframework.security.core.Authentication;
-
-/**
- * An {@link Advice} which can determine if an {@link Authentication} has access to the
- * returned object from the {@link MethodInvocation}. {@link #getPointcut()} describes
- * when the advice applies for the method.
- *
- * @param <T> the type of object that the authorization check is being done one.
- * @author Evgeniy Cheban
- * @author Josh Cummings
- * @since 5.5
- */
-public interface AuthorizationMethodAfterAdvice<T> extends AfterAdvice, PointcutAdvisor, AopInfrastructureBean {
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	default boolean isPerInstance() {
-		return true;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	default Advice getAdvice() {
-		return this;
-	}
-
-	/**
-	 * Determine if an {@link Authentication} has access to a method invocation's return
-	 * object.
-	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param object the {@link T} object to check
-	 * @param returnedObject the returned object from the method invocation to check
-	 * @return the {@code Object} that will ultimately be returned to the caller (if an
-	 * implementation does not wish to modify the object to be returned to the caller, the
-	 * implementation should simply return the same object it was passed by the
-	 * {@code returnedObject} method argument)
-	 */
-	Object after(Supplier<Authentication> authentication, T object, Object returnedObject);
-
-}

+ 0 - 62
core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodBeforeAdvice.java

@@ -1,62 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * 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
- *
- *      https://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 org.springframework.security.authorization.method;
-
-import java.util.function.Supplier;
-
-import org.aopalliance.aop.Advice;
-
-import org.springframework.aop.BeforeAdvice;
-import org.springframework.aop.PointcutAdvisor;
-import org.springframework.aop.framework.AopInfrastructureBean;
-import org.springframework.security.core.Authentication;
-
-/**
- * An {@link Advice} which can determine if an {@link Authentication} has access to the
- * {@link T} object. {@link #getPointcut()} describes when the advice applies.
- *
- * @param <T> the type of object that the authorization check is being done one.
- * @author Evgeniy Cheban
- * @author Josh Cummings
- * @since 5.5
- */
-public interface AuthorizationMethodBeforeAdvice<T> extends BeforeAdvice, PointcutAdvisor, AopInfrastructureBean {
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	default boolean isPerInstance() {
-		return true;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	default Advice getAdvice() {
-		return this;
-	}
-
-	/**
-	 * Determine if an {@link Authentication} has access to the {@link T} object.
-	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param object the {@link T} object to check
-	 */
-	void before(Supplier<Authentication> authentication, T object);
-
-}

+ 41 - 36
core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodInterceptor.java

@@ -16,65 +16,70 @@
 
 package org.springframework.security.authorization.method;
 
+import java.util.function.Supplier;
+
+import org.aopalliance.aop.Advice;
 import org.aopalliance.intercept.MethodInterceptor;
 import org.aopalliance.intercept.MethodInvocation;
 
-import org.springframework.aop.support.AopUtils;
-import org.springframework.lang.NonNull;
+import org.springframework.aop.PointcutAdvisor;
+import org.springframework.aop.framework.AopInfrastructureBean;
 import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 
 /**
- * Provides security interception of AOP Alliance based method invocations.
+ * A {@link MethodInterceptor} which can determine if an {@link Authentication} has access
+ * to the {@link MethodInvocation}. {@link #getPointcut()} describes when the interceptor
+ * applies.
  *
  * @author Evgeniy Cheban
+ * @author Josh Cummings
  * @since 5.5
  */
-public final class AuthorizationMethodInterceptor implements MethodInterceptor {
-
-	private final AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> beforeAdvice;
-
-	private final AuthorizationMethodAfterAdvice<MethodAuthorizationContext> afterAdvice;
+public interface AuthorizationMethodInterceptor extends MethodInterceptor, PointcutAdvisor, AopInfrastructureBean {
 
 	/**
-	 * Creates an instance.
-	 * @param beforeAdvice the {@link AuthorizationMethodBeforeAdvice} to use
-	 * @param afterAdvice the {@link AuthorizationMethodAfterAdvice} to use
+	 * {@inheritDoc}
 	 */
-	public AuthorizationMethodInterceptor(AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> beforeAdvice,
-			AuthorizationMethodAfterAdvice<MethodAuthorizationContext> afterAdvice) {
-		this.beforeAdvice = beforeAdvice;
-		this.afterAdvice = afterAdvice;
+	@Override
+	default Advice getAdvice() {
+		return this;
 	}
 
 	/**
-	 * Enforce security on this {@link MethodInvocation}.
-	 * @param mi the method being invoked which requires a security decision
-	 * @return the returned value from the {@link MethodInvocation}, possibly altered by
-	 * the configured {@link AuthorizationMethodAfterAdvice}
+	 * {@inheritDoc}
 	 */
 	@Override
-	public Object invoke(@NonNull MethodInvocation mi) throws Throwable {
-		MethodAuthorizationContext methodAuthorizationContext = getMethodAuthorizationContext(mi);
-		this.beforeAdvice.before(this::getAuthentication, methodAuthorizationContext);
-		Object returnedObject = mi.proceed();
-		return this.afterAdvice.after(this::getAuthentication, methodAuthorizationContext, returnedObject);
+	default boolean isPerInstance() {
+		return true;
 	}
 
-	private MethodAuthorizationContext getMethodAuthorizationContext(MethodInvocation mi) {
-		Object target = mi.getThis();
-		Class<?> targetClass = (target != null) ? AopUtils.getTargetClass(target) : null;
-		return new MethodAuthorizationContext(mi, targetClass);
+	/**
+	 * Determine if an {@link Authentication} has access to the {@link MethodInvocation}
+	 * @param mi the {@link MethodInvocation} to intercept and potentially invoke
+	 * @return the result of the method invocation
+	 * @throws Throwable if the interceptor or the target object throws an exception
+	 */
+	default Object invoke(MethodInvocation mi) throws Throwable {
+		Supplier<Authentication> supplier = () -> {
+			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+			if (authentication == null) {
+				throw new AuthenticationCredentialsNotFoundException(
+						"An Authentication object was not found in the SecurityContext");
+			}
+			return authentication;
+		};
+		return invoke(supplier, new AuthorizationMethodInvocation(supplier, mi));
 	}
 
-	private Authentication getAuthentication() {
-		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
-		if (authentication == null) {
-			throw new AuthenticationCredentialsNotFoundException(
-					"An Authentication object was not found in the SecurityContext");
-		}
-		return authentication;
-	}
+	/**
+	 * Determine if an {@link Authentication} has access to the {@link MethodInvocation}
+	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
+	 * @param mi the {@link MethodInvocation} to intercept and potentially invoke
+	 * @return the result of the method invocation
+	 * @throws Throwable if the interceptor or the target object throws an exception
+	 */
+	Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable;
 
 }

+ 80 - 0
core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodInterceptors.java

@@ -0,0 +1,80 @@
+/*
+ * Copyright 2002-2021 the original author or authors.
+ *
+ * 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
+ *
+ *      https://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 org.springframework.security.authorization.method;
+
+import javax.annotation.security.DenyAll;
+import javax.annotation.security.PermitAll;
+import javax.annotation.security.RolesAllowed;
+
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.security.access.prepost.PostAuthorize;
+import org.springframework.security.access.prepost.PreAuthorize;
+
+/**
+ * A static factory for constructing common {@link AuthorizationMethodInterceptor}s
+ *
+ * @author Josh Cummings
+ * @since 5.5
+ * @see PreAuthorizeAuthorizationManager
+ * @see PostAuthorizeAuthorizationManager
+ * @see SecuredAuthorizationManager
+ * @see Jsr250AuthorizationManager
+ */
+public final class AuthorizationMethodInterceptors {
+
+	public static AuthorizationMethodInterceptor preAuthorize() {
+		return preAuthorize(new PreAuthorizeAuthorizationManager());
+	}
+
+	public static AuthorizationMethodInterceptor preAuthorize(PreAuthorizeAuthorizationManager manager) {
+		return new AuthorizationManagerBeforeMethodInterceptor(
+				AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class), manager);
+	}
+
+	public static AuthorizationMethodInterceptor postAuthorize() {
+		return postAuthorize(new PostAuthorizeAuthorizationManager());
+	}
+
+	public static AuthorizationMethodInterceptor postAuthorize(PostAuthorizeAuthorizationManager manager) {
+		return new AuthorizationManagerAfterMethodInterceptor(
+				AuthorizationMethodPointcuts.forAnnotations(PostAuthorize.class), manager);
+	}
+
+	public static AuthorizationMethodInterceptor secured() {
+		return secured(new SecuredAuthorizationManager());
+	}
+
+	public static AuthorizationMethodInterceptor secured(SecuredAuthorizationManager manager) {
+		return new AuthorizationManagerBeforeMethodInterceptor(
+				AuthorizationMethodPointcuts.forAnnotations(Secured.class), manager);
+	}
+
+	public static AuthorizationMethodInterceptor jsr250() {
+		return jsr250(new Jsr250AuthorizationManager());
+	}
+
+	public static AuthorizationMethodInterceptor jsr250(Jsr250AuthorizationManager manager) {
+		return new AuthorizationManagerBeforeMethodInterceptor(
+				AuthorizationMethodPointcuts.forAnnotations(DenyAll.class, PermitAll.class, RolesAllowed.class),
+				manager);
+	}
+
+	private AuthorizationMethodInterceptors() {
+
+	}
+
+}

+ 123 - 0
core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodInvocation.java

@@ -0,0 +1,123 @@
+/*
+ * Copyright 2002-2021 the original author or authors.
+ *
+ * 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
+ *
+ *      https://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 org.springframework.security.authorization.method;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.aop.Pointcut;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.core.log.LogMessage;
+import org.springframework.security.core.Authentication;
+
+/**
+ * @author Josh Cummings
+ */
+class AuthorizationMethodInvocation implements MethodInvocation {
+
+	private final Log logger = LogFactory.getLog(getClass());
+
+	private final Supplier<Authentication> authentication;
+
+	private final MethodInvocation methodInvocation;
+
+	private final Class<?> targetClass;
+
+	private final List<AuthorizationMethodInterceptor> interceptors;
+
+	private final int size;
+
+	private int currentPosition = 0;
+
+	AuthorizationMethodInvocation(Supplier<Authentication> authentication, MethodInvocation methodInvocation) {
+		this(authentication, methodInvocation, Collections.emptyList());
+	}
+
+	AuthorizationMethodInvocation(Supplier<Authentication> authentication, MethodInvocation methodInvocation,
+			List<AuthorizationMethodInterceptor> interceptors) {
+		this.authentication = authentication;
+		this.methodInvocation = methodInvocation;
+		this.interceptors = interceptors;
+		Object target = methodInvocation.getThis();
+		this.targetClass = (target != null) ? AopUtils.getTargetClass(target) : null;
+		this.size = interceptors.size();
+	}
+
+	@Override
+	public Method getMethod() {
+		return this.methodInvocation.getMethod();
+	}
+
+	@Override
+	public Object[] getArguments() {
+		return this.methodInvocation.getArguments();
+	}
+
+	/**
+	 * Return the target class.
+	 * @return the target class
+	 */
+	Class<?> getTargetClass() {
+		return this.targetClass;
+	}
+
+	@Override
+	public Object proceed() throws Throwable {
+		if (this.currentPosition == this.size) {
+			if (this.logger.isDebugEnabled()) {
+				this.logger.debug(LogMessage.of(() -> "Pre-Authorized " + this.methodInvocation.getMethod()));
+			}
+			return this.methodInvocation.proceed();
+		}
+		AuthorizationMethodInterceptor interceptor = this.interceptors.get(this.currentPosition);
+		this.currentPosition++;
+		Pointcut pointcut = interceptor.getPointcut();
+		if (!pointcut.getClassFilter().matches(getTargetClass())) {
+			return proceed();
+		}
+		if (!pointcut.getMethodMatcher().matches(getMethod(), getTargetClass())) {
+			return proceed();
+		}
+		if (this.logger.isTraceEnabled()) {
+			this.logger.trace(LogMessage.format("Applying %s (%d/%d)", interceptor.getClass().getSimpleName(),
+					this.currentPosition, this.size));
+		}
+		Object result = interceptor.invoke(this.authentication, this);
+		if (this.logger.isDebugEnabled()) {
+			this.logger.debug(LogMessage.of(() -> "Post-Authorized " + this.methodInvocation.getMethod()));
+		}
+		return result;
+	}
+
+	@Override
+	public Object getThis() {
+		return this.methodInvocation.getThis();
+	}
+
+	@Override
+	public AccessibleObject getStaticPart() {
+		return this.methodInvocation.getStaticPart();
+	}
+
+}

+ 54 - 0
core/src/main/java/org/springframework/security/authorization/method/AuthorizationMethodPointcuts.java

@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002-2021 the original author or authors.
+ *
+ * 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
+ *
+ *      https://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 org.springframework.security.authorization.method;
+
+import java.lang.annotation.Annotation;
+
+import org.springframework.aop.Pointcut;
+import org.springframework.aop.support.ComposablePointcut;
+import org.springframework.aop.support.Pointcuts;
+import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
+
+/**
+ * @author Josh Cummings
+ */
+final class AuthorizationMethodPointcuts {
+
+	@SafeVarargs
+	static Pointcut forAnnotations(Class<? extends Annotation>... annotations) {
+		ComposablePointcut pointcut = null;
+		for (Class<? extends Annotation> annotation : annotations) {
+			if (pointcut == null) {
+				pointcut = new ComposablePointcut(classOrMethod(annotation));
+			}
+			else {
+				pointcut.union(classOrMethod(annotation));
+			}
+		}
+		return pointcut;
+	}
+
+	private static Pointcut classOrMethod(Class<? extends Annotation> annotation) {
+		return Pointcuts.union(new AnnotationMatchingPointcut(null, annotation, true),
+				new AnnotationMatchingPointcut(annotation, true));
+	}
+
+	private AuthorizationMethodPointcuts() {
+
+	}
+
+}

+ 0 - 106
core/src/main/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodAfterAdvice.java

@@ -1,106 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * 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
- *
- *      https://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 org.springframework.security.authorization.method;
-
-import java.util.List;
-import java.util.function.Supplier;
-
-import org.aopalliance.intercept.MethodInvocation;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.aop.Pointcut;
-import org.springframework.aop.support.ComposablePointcut;
-import org.springframework.core.log.LogMessage;
-import org.springframework.security.core.Authentication;
-import org.springframework.util.Assert;
-
-/**
- * An {@link AuthorizationMethodAfterAdvice} which delegates to specific
- * {@link AuthorizationMethodAfterAdvice}s and returns the result (possibly modified) from
- * the {@link MethodInvocation}.
- *
- * @author Evgeniy Cheban
- * @author Josh Cummings
- * @since 5.5
- */
-public final class DelegatingAuthorizationMethodAfterAdvice<T> implements AuthorizationMethodAfterAdvice<T> {
-
-	private final Log logger = LogFactory.getLog(getClass());
-
-	private final Pointcut pointcut;
-
-	private final List<AuthorizationMethodAfterAdvice<T>> delegates;
-
-	/**
-	 * Creates an instance.
-	 * @param delegates the {@link AuthorizationMethodAfterAdvice}s to use
-	 */
-	public DelegatingAuthorizationMethodAfterAdvice(List<AuthorizationMethodAfterAdvice<T>> delegates) {
-		Assert.notEmpty(delegates, "delegates cannot be empty");
-		this.delegates = delegates;
-		ComposablePointcut pointcut = null;
-		for (AuthorizationMethodAfterAdvice<?> advice : delegates) {
-			if (pointcut == null) {
-				pointcut = new ComposablePointcut(advice.getPointcut());
-			}
-			else {
-				pointcut.union(advice.getPointcut());
-			}
-		}
-		this.pointcut = pointcut;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Pointcut getPointcut() {
-		return this.pointcut;
-	}
-
-	/**
-	 * Delegate to a series of {@link AuthorizationMethodAfterAdvice}s, each of which may
-	 * replace the {@code returnedObject} with its own
-	 *
-	 * Advices may be of type {@link AuthorizationManagerMethodAfterAdvice} in which case,
-	 * they will throw an
-	 * {@link org.springframework.security.access.AccessDeniedException} in the event that
-	 * they deny access to the {@code returnedObject}.
-	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param object the {@link MethodAuthorizationContext} to check
-	 * @param returnedObject the returned object from the original method invocation
-	 * @throws org.springframework.security.access.AccessDeniedException if any delegate
-	 * advices deny access
-	 */
-	@Override
-	public Object after(Supplier<Authentication> authentication, T object, Object returnedObject) {
-		if (this.logger.isTraceEnabled()) {
-			this.logger.trace(LogMessage.format("Post Authorizing %s from %s", returnedObject, object));
-		}
-		Object result = returnedObject;
-		for (AuthorizationMethodAfterAdvice<T> delegate : this.delegates) {
-			if (this.logger.isTraceEnabled()) {
-				this.logger.trace(
-						LogMessage.format("Checking authorization on %s from %s using %s", result, object, delegate));
-			}
-			result = delegate.after(authentication, object, result);
-		}
-		return result;
-	}
-
-}

+ 0 - 101
core/src/main/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodBeforeAdvice.java

@@ -1,101 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * 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
- *
- *      https://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 org.springframework.security.authorization.method;
-
-import java.util.List;
-import java.util.function.Supplier;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.aop.Pointcut;
-import org.springframework.aop.support.ComposablePointcut;
-import org.springframework.core.log.LogMessage;
-import org.springframework.security.core.Authentication;
-import org.springframework.util.Assert;
-
-/**
- * An {@link AuthorizationMethodBeforeAdvice} which delegates to a specific
- * {@link AuthorizationMethodBeforeAdvice} and grants access if all
- * {@link AuthorizationMethodBeforeAdvice}s granted or abstained. Denies access only if
- * one of the {@link AuthorizationMethodBeforeAdvice}s denied.
- *
- * @author Evgeniy Cheban
- * @author Josh Cummings
- * @since 5.5
- */
-public final class DelegatingAuthorizationMethodBeforeAdvice<T> implements AuthorizationMethodBeforeAdvice<T> {
-
-	private final Log logger = LogFactory.getLog(getClass());
-
-	private final Pointcut pointcut;
-
-	private final List<AuthorizationMethodBeforeAdvice<T>> delegates;
-
-	/**
-	 * Creates an instance.
-	 * @param delegates the {@link AuthorizationMethodBeforeAdvice}s to use
-	 */
-	public DelegatingAuthorizationMethodBeforeAdvice(List<AuthorizationMethodBeforeAdvice<T>> delegates) {
-		Assert.notEmpty(delegates, "delegates cannot be empty");
-		this.delegates = delegates;
-		ComposablePointcut pointcut = null;
-		for (AuthorizationMethodBeforeAdvice<?> advice : delegates) {
-			if (pointcut == null) {
-				pointcut = new ComposablePointcut(advice.getPointcut());
-			}
-			else {
-				pointcut.union(advice.getPointcut());
-			}
-		}
-		this.pointcut = pointcut;
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Pointcut getPointcut() {
-		return this.pointcut;
-	}
-
-	/**
-	 * Delegate to a series of {@link AuthorizationMethodBeforeAdvice}s
-	 *
-	 * Advices may be of type {@link AuthorizationManagerMethodBeforeAdvice} in which
-	 * case, they will throw an
-	 * {@link org.springframework.security.access.AccessDeniedException} in the event that
-	 * they deny access.
-	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param object the {@link MethodAuthorizationContext} to check
-	 * @throws org.springframework.security.access.AccessDeniedException if any delegate
-	 * advices deny access
-	 */
-	@Override
-	public void before(Supplier<Authentication> authentication, T object) {
-		if (this.logger.isTraceEnabled()) {
-			this.logger.trace(LogMessage.format("Pre Authorizing %s", object));
-		}
-		for (AuthorizationMethodBeforeAdvice<T> delegate : this.delegates) {
-			if (this.logger.isTraceEnabled()) {
-				this.logger.trace(LogMessage.format("Checking authorization on %s using %s", object, delegate));
-			}
-			delegate.before(authentication, object);
-		}
-	}
-
-}

+ 89 - 0
core/src/main/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodInterceptor.java

@@ -0,0 +1,89 @@
+/*
+ * Copyright 2002-2021 the original author or authors.
+ *
+ * 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
+ *
+ *      https://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 org.springframework.security.authorization.method;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.aop.Pointcut;
+import org.springframework.aop.support.ComposablePointcut;
+import org.springframework.security.core.Authentication;
+
+/**
+ * Provides security interception of AOP Alliance based method invocations.
+ *
+ * Delegates to a collection of {@link AuthorizationMethodInterceptor}s
+ *
+ * @author Evgeniy Cheban
+ * @author Josh Cummings
+ * @since 5.5
+ */
+public final class DelegatingAuthorizationMethodInterceptor implements AuthorizationMethodInterceptor {
+
+	private final List<AuthorizationMethodInterceptor> interceptors;
+
+	private final Pointcut pointcut;
+
+	/**
+	 * Creates an instance using the provided parameters
+	 * @param interceptors the delegate {@link AuthorizationMethodInterceptor}s to use
+	 */
+	public DelegatingAuthorizationMethodInterceptor(AuthorizationMethodInterceptor... interceptors) {
+		this(Arrays.asList(interceptors));
+	}
+
+	/**
+	 * Creates an instance using the provided parameters
+	 * @param interceptors the delegate {@link AuthorizationMethodInterceptor}s to use
+	 */
+	public DelegatingAuthorizationMethodInterceptor(List<AuthorizationMethodInterceptor> interceptors) {
+		ComposablePointcut pointcut = null;
+		for (AuthorizationMethodInterceptor interceptor : interceptors) {
+			if (pointcut == null) {
+				pointcut = new ComposablePointcut(interceptor.getPointcut());
+			}
+			else {
+				pointcut.union(interceptor.getPointcut());
+			}
+		}
+		this.pointcut = pointcut;
+		this.interceptors = interceptors;
+	}
+
+	/**
+	 * Enforce security on this {@link MethodInvocation}.
+	 * @param mi the method being invoked which requires a security decision
+	 * @return the returned value from the {@link MethodInvocation}, possibly altered by
+	 * the configured {@link AuthorizationMethodInterceptor}s
+	 */
+	@Override
+	public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
+		return new AuthorizationMethodInvocation(authentication, mi, this.interceptors).proceed();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Pointcut getPointcut() {
+		return this.pointcut;
+	}
+
+}

+ 10 - 11
core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java

@@ -39,14 +39,14 @@ import org.springframework.security.core.Authentication;
 import org.springframework.util.Assert;
 
 /**
- * An {@link AuthorizationManager} which can determine if an {@link Authentication} has
- * access to the {@link MethodInvocation} by evaluating if the {@link Authentication}
+ * An {@link AuthorizationManager} which can determine if an {@link Authentication} may
+ * invoke the {@link MethodInvocation} by evaluating if the {@link Authentication}
  * contains a specified authority from the JSR-250 security annotations.
  *
  * @author Evgeniy Cheban
  * @since 5.5
  */
-public final class Jsr250AuthorizationManager implements AuthorizationManager<MethodAuthorizationContext> {
+public final class Jsr250AuthorizationManager implements AuthorizationManager<MethodInvocation> {
 
 	private static final Set<Class<? extends Annotation>> JSR250_ANNOTATIONS = new HashSet<>();
 
@@ -72,25 +72,24 @@ public final class Jsr250AuthorizationManager implements AuthorizationManager<Me
 	/**
 	 * Determine if an {@link Authentication} has access to a method by evaluating the
 	 * {@link DenyAll}, {@link PermitAll}, and {@link RolesAllowed} annotations that
-	 * {@link MethodAuthorizationContext} specifies.
+	 * {@link AuthorizationMethodInvocation} specifies.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
+	 * @param methodInvocation the {@link AuthorizationMethodInvocation} to check
 	 * @return an {@link AuthorizationDecision} or null if the JSR-250 security
 	 * annotations is not present
 	 */
 	@Override
-	public AuthorizationDecision check(Supplier<Authentication> authentication,
-			MethodAuthorizationContext methodAuthorizationContext) {
-		AuthorizationManager<MethodAuthorizationContext> delegate = this.registry
-				.getManager(methodAuthorizationContext);
-		return delegate.check(authentication, methodAuthorizationContext);
+	public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation methodInvocation) {
+		AuthorizationManager<MethodInvocation> delegate = this.registry
+				.getManager((AuthorizationMethodInvocation) methodInvocation);
+		return delegate.check(authentication, methodInvocation);
 	}
 
 	private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
 
 		@NonNull
 		@Override
-		AuthorizationManager<MethodAuthorizationContext> resolveManager(Method method, Class<?> targetClass) {
+		AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
 			for (Annotation annotation : findJsr250Annotations(method, targetClass)) {
 				if (annotation instanceof DenyAll) {
 					return (a, o) -> new AuthorizationDecision(false);

+ 0 - 66
core/src/main/java/org/springframework/security/authorization/method/MethodAuthorizationContext.java

@@ -1,66 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * 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
- *
- *      https://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 org.springframework.security.authorization.method;
-
-import org.aopalliance.intercept.MethodInvocation;
-
-/**
- * An authorization context which is holds the {@link MethodInvocation} and the target
- * class
- *
- * @author Evgeniy Cheban
- * @since 5.5
- */
-public final class MethodAuthorizationContext {
-
-	private final MethodInvocation methodInvocation;
-
-	private final Class<?> targetClass;
-
-	/**
-	 * Creates an instance.
-	 * @param methodInvocation the {@link MethodInvocation} to use
-	 * @param targetClass the target class to use
-	 */
-	public MethodAuthorizationContext(MethodInvocation methodInvocation, Class<?> targetClass) {
-		this.methodInvocation = methodInvocation;
-		this.targetClass = targetClass;
-	}
-
-	/**
-	 * Return the {@link MethodInvocation}.
-	 * @return the {@link MethodInvocation}
-	 */
-	public MethodInvocation getMethodInvocation() {
-		return this.methodInvocation;
-	}
-
-	/**
-	 * Return the target class.
-	 * @return the target class
-	 */
-	public Class<?> getTargetClass() {
-		return this.targetClass;
-	}
-
-	@Override
-	public String toString() {
-		return "MethodAuthorizationContext[methodInvocation=" + this.methodInvocation + ", targetClass="
-				+ this.targetClass + ']';
-	}
-
-}

+ 11 - 13
core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManager.java

@@ -36,22 +36,21 @@ import org.springframework.security.core.Authentication;
 import org.springframework.util.Assert;
 
 /**
- * An {@link AuthorizationManager} which can determine if an {@link Authentication} has
- * access to the {@link MethodInvocation} by evaluating an expression from the
- * {@link PostAuthorize} annotation.
+ * An {@link AuthorizationManager} which can determine if an {@link Authentication} may
+ * return the result from an invoked {@link MethodInvocation} by evaluating an expression
+ * from the {@link PostAuthorize} annotation.
  *
  * @author Evgeniy Cheban
  * @since 5.5
  */
-public final class PostAuthorizeAuthorizationManager
-		implements AfterMethodAuthorizationManager<MethodAuthorizationContext> {
+public final class PostAuthorizeAuthorizationManager implements AfterMethodAuthorizationManager<MethodInvocation> {
 
 	private final PostAuthorizeExpressionAttributeRegistry registry = new PostAuthorizeExpressionAttributeRegistry();
 
 	private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
 
 	/**
-	 * Sets the {@link MethodSecurityExpressionHandler}.
+	 * Use this the {@link MethodSecurityExpressionHandler}.
 	 * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
 	 */
 	public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
@@ -62,22 +61,21 @@ public final class PostAuthorizeAuthorizationManager
 	/**
 	 * Determine if an {@link Authentication} has access to the returned object by
 	 * evaluating the {@link PostAuthorize} annotation that the
-	 * {@link MethodAuthorizationContext} specifies.
+	 * {@link AuthorizationMethodInvocation} specifies.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
+	 * @param mi the {@link AuthorizationMethodInvocation} to check
 	 * @param returnedObject the returned object to check
 	 * @return an {@link AuthorizationDecision} or {@code null} if the
 	 * {@link PostAuthorize} annotation is not present
 	 */
 	@Override
-	public AuthorizationDecision check(Supplier<Authentication> authentication,
-			MethodAuthorizationContext methodAuthorizationContext, Object returnedObject) {
-		ExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
+	public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi,
+			Object returnedObject) {
+		ExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
 		if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
 			return null;
 		}
-		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(),
-				methodAuthorizationContext.getMethodInvocation());
+		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
 		this.expressionHandler.setReturnObject(returnedObject, ctx);
 		boolean granted = ExpressionUtils.evaluateAsBoolean(attribute.getExpression(), ctx);
 		return new AuthorizationDecision(granted);

+ 15 - 22
core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodAfterAdvice.java → core/src/main/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptor.java

@@ -34,16 +34,15 @@ import org.springframework.security.core.Authentication;
 import org.springframework.util.Assert;
 
 /**
- * An {@link AuthorizationMethodAfterAdvice} which filters a <code>returnedObject</code>
- * from the {@link MethodInvocation} by evaluating an expression from the
- * {@link PostFilter} annotation.
+ * An {@link AuthorizationMethodInterceptor} which filters a {@code returnedObject} from
+ * the {@link MethodInvocation} by evaluating an expression from the {@link PostFilter}
+ * annotation.
  *
  * @author Evgeniy Cheban
  * @author Josh Cummings
  * @since 5.5
  */
-public final class PostFilterAuthorizationMethodAfterAdvice
-		implements AuthorizationMethodAfterAdvice<MethodAuthorizationContext> {
+public final class PostFilterAuthorizationMethodInterceptor implements AuthorizationMethodInterceptor {
 
 	private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry();
 
@@ -52,16 +51,15 @@ public final class PostFilterAuthorizationMethodAfterAdvice
 	private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
 
 	/**
-	 * Create a {@link PostFilterAuthorizationMethodAfterAdvice} using the provided
+	 * Creates a {@link PostFilterAuthorizationMethodInterceptor} using the provided
 	 * parameters
-	 * @param pointcut the {@link Pointcut} for when this advice applies
 	 */
-	public PostFilterAuthorizationMethodAfterAdvice(Pointcut pointcut) {
-		this.pointcut = pointcut;
+	public PostFilterAuthorizationMethodInterceptor() {
+		this.pointcut = AuthorizationMethodPointcuts.forAnnotations(PostFilter.class);
 	}
 
 	/**
-	 * Sets the {@link MethodSecurityExpressionHandler}.
+	 * Use this {@link MethodSecurityExpressionHandler}.
 	 * @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
 	 */
 	public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
@@ -79,24 +77,19 @@ public final class PostFilterAuthorizationMethodAfterAdvice
 
 	/**
 	 * Filter a {@code returnedObject} using the {@link PostFilter} annotation that the
-	 * {@link MethodAuthorizationContext} specifies.
+	 * {@link AuthorizationMethodInvocation} specifies.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
-	 * check
+	 * @param mi the {@link AuthorizationMethodInvocation} to check check
 	 * @return filtered {@code returnedObject}
 	 */
 	@Override
-	public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext methodAuthorizationContext,
-			Object returnedObject) {
-		if (returnedObject == null) {
-			return null;
-		}
-		ExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
+	public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
+		Object returnedObject = mi.proceed();
+		ExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
 		if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
 			return returnedObject;
 		}
-		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(),
-				methodAuthorizationContext.getMethodInvocation());
+		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
 		return this.expressionHandler.filter(returnedObject, attribute.getExpression(), ctx);
 	}
 
@@ -111,7 +104,7 @@ public final class PostFilterAuthorizationMethodAfterAdvice
 			if (postFilter == null) {
 				return ExpressionAttribute.NULL_ATTRIBUTE;
 			}
-			Expression postFilterExpression = PostFilterAuthorizationMethodAfterAdvice.this.expressionHandler
+			Expression postFilterExpression = PostFilterAuthorizationMethodInterceptor.this.expressionHandler
 					.getExpressionParser().parseExpression(postFilter.value());
 			return new ExpressionAttribute(postFilterExpression);
 		}

+ 8 - 10
core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManager.java

@@ -36,14 +36,14 @@ import org.springframework.security.core.Authentication;
 import org.springframework.util.Assert;
 
 /**
- * An {@link AuthorizationManager} which can determine if an {@link Authentication} has
- * access to the {@link MethodInvocation} by evaluating an expression from the
+ * An {@link AuthorizationManager} which can determine if an {@link Authentication} may
+ * invoke the {@link MethodInvocation} by evaluating an expression from the
  * {@link PreAuthorize} annotation.
  *
  * @author Evgeniy Cheban
  * @since 5.5
  */
-public final class PreAuthorizeAuthorizationManager implements AuthorizationManager<MethodAuthorizationContext> {
+public final class PreAuthorizeAuthorizationManager implements AuthorizationManager<MethodInvocation> {
 
 	private final PreAuthorizeExpressionAttributeRegistry registry = new PreAuthorizeExpressionAttributeRegistry();
 
@@ -61,21 +61,19 @@ public final class PreAuthorizeAuthorizationManager implements AuthorizationMana
 	/**
 	 * Determine if an {@link Authentication} has access to a method by evaluating an
 	 * expression from the {@link PreAuthorize} annotation that the
-	 * {@link MethodAuthorizationContext} specifies.
+	 * {@link AuthorizationMethodInvocation} specifies.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
+	 * @param mi the {@link AuthorizationMethodInvocation} to check
 	 * @return an {@link AuthorizationDecision} or {@code null} if the
 	 * {@link PreAuthorize} annotation is not present
 	 */
 	@Override
-	public AuthorizationDecision check(Supplier<Authentication> authentication,
-			MethodAuthorizationContext methodAuthorizationContext) {
-		ExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
+	public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
+		ExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
 		if (attribute == ExpressionAttribute.NULL_ATTRIBUTE) {
 			return null;
 		}
-		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(),
-				methodAuthorizationContext.getMethodInvocation());
+		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
 		boolean granted = ExpressionUtils.evaluateAsBoolean(attribute.getExpression(), ctx);
 		return new AuthorizationDecision(granted);
 	}

+ 13 - 15
core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodBeforeAdvice.java → core/src/main/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptor.java

@@ -35,15 +35,14 @@ import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
 /**
- * An {@link AuthorizationMethodBeforeAdvice} which filters a method argument by
- * evaluating an expression from the {@link PreFilter} annotation.
+ * An {@link AuthorizationMethodInterceptor} which filters a method argument by evaluating
+ * an expression from the {@link PreFilter} annotation.
  *
  * @author Evgeniy Cheban
  * @author Josh Cummings
  * @since 5.5
  */
-public final class PreFilterAuthorizationMethodBeforeAdvice
-		implements AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> {
+public final class PreFilterAuthorizationMethodInterceptor implements AuthorizationMethodInterceptor {
 
 	private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry();
 
@@ -52,12 +51,11 @@ public final class PreFilterAuthorizationMethodBeforeAdvice
 	private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
 
 	/**
-	 * Creates a {@link PreFilterAuthorizationMethodBeforeAdvice} using the provided
+	 * Creates a {@link PreFilterAuthorizationMethodInterceptor} using the provided
 	 * parameters
-	 * @param pointcut the {@link Pointcut} for when this advice applies
 	 */
-	public PreFilterAuthorizationMethodBeforeAdvice(Pointcut pointcut) {
-		this.pointcut = pointcut;
+	public PreFilterAuthorizationMethodInterceptor() {
+		this.pointcut = AuthorizationMethodPointcuts.forAnnotations(PreFilter.class);
 	}
 
 	/**
@@ -79,20 +77,20 @@ public final class PreFilterAuthorizationMethodBeforeAdvice
 
 	/**
 	 * Filter the method argument specified in the {@link PreFilter} annotation that
-	 * {@link MethodAuthorizationContext} specifies.
+	 * {@link AuthorizationMethodInvocation} specifies.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
+	 * @param mi the {@link AuthorizationMethodInvocation} to check
 	 */
 	@Override
-	public void before(Supplier<Authentication> authentication, MethodAuthorizationContext methodAuthorizationContext) {
-		PreFilterExpressionAttribute attribute = this.registry.getAttribute(methodAuthorizationContext);
+	public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) throws Throwable {
+		PreFilterExpressionAttribute attribute = this.registry.getAttribute((AuthorizationMethodInvocation) mi);
 		if (attribute == PreFilterExpressionAttribute.NULL_ATTRIBUTE) {
-			return;
+			return mi.proceed();
 		}
-		MethodInvocation mi = methodAuthorizationContext.getMethodInvocation();
 		EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication.get(), mi);
 		Object filterTarget = findFilterTarget(attribute.filterTarget, ctx, mi);
 		this.expressionHandler.filter(filterTarget, attribute.getExpression(), ctx);
+		return mi.proceed();
 	}
 
 	private Object findFilterTarget(String filterTargetName, EvaluationContext ctx, MethodInvocation methodInvocation) {
@@ -126,7 +124,7 @@ public final class PreFilterAuthorizationMethodBeforeAdvice
 			if (preFilter == null) {
 				return PreFilterExpressionAttribute.NULL_ATTRIBUTE;
 			}
-			Expression preFilterExpression = PreFilterAuthorizationMethodBeforeAdvice.this.expressionHandler
+			Expression preFilterExpression = PreFilterAuthorizationMethodInterceptor.this.expressionHandler
 					.getExpressionParser().parseExpression(preFilter.value());
 			return new PreFilterExpressionAttribute(preFilterExpression, preFilter.filterTarget());
 		}

+ 9 - 11
core/src/main/java/org/springframework/security/authorization/method/SecuredAuthorizationManager.java

@@ -31,38 +31,36 @@ import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.core.Authentication;
 
 /**
- * An {@link AuthorizationManager} which can determine if an {@link Authentication} has
- * access to the {@link MethodInvocation} by evaluating if the {@link Authentication}
+ * An {@link AuthorizationManager} which can determine if an {@link Authentication} may
+ * invoke the {@link MethodInvocation} by evaluating if the {@link Authentication}
  * contains a specified authority from the Spring Security's {@link Secured} annotation.
  *
  * @author Evgeniy Cheban
  * @since 5.5
  */
-public final class SecuredAuthorizationManager implements AuthorizationManager<MethodAuthorizationContext> {
+public final class SecuredAuthorizationManager implements AuthorizationManager<MethodInvocation> {
 
 	private final SecuredAuthorizationManagerRegistry registry = new SecuredAuthorizationManagerRegistry();
 
 	/**
 	 * Determine if an {@link Authentication} has access to a method by evaluating the
-	 * {@link Secured} annotation that {@link MethodAuthorizationContext} specifies.
+	 * {@link Secured} annotation that {@link AuthorizationMethodInvocation} specifies.
 	 * @param authentication the {@link Supplier} of the {@link Authentication} to check
-	 * @param methodAuthorizationContext the {@link MethodAuthorizationContext} to check
+	 * @param mi the {@link AuthorizationMethodInvocation} to check
 	 * @return an {@link AuthorizationDecision} or null if the {@link Secured} annotation
 	 * is not present
 	 */
 	@Override
-	public AuthorizationDecision check(Supplier<Authentication> authentication,
-			MethodAuthorizationContext methodAuthorizationContext) {
-		AuthorizationManager<MethodAuthorizationContext> delegate = this.registry
-				.getManager(methodAuthorizationContext);
-		return delegate.check(authentication, methodAuthorizationContext);
+	public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
+		AuthorizationManager<MethodInvocation> delegate = this.registry.getManager((AuthorizationMethodInvocation) mi);
+		return delegate.check(authentication, mi);
 	}
 
 	private static final class SecuredAuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
 
 		@NonNull
 		@Override
-		AuthorizationManager<MethodAuthorizationContext> resolveManager(Method method, Class<?> targetClass) {
+		AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
 			Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
 			Secured secured = findSecuredAnnotation(specificMethod);
 			return (secured != null) ? AuthorityAuthorizationManager.hasAnyAuthority(secured.value()) : NULL_MANAGER;

+ 10 - 8
core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerMethodAfterAdviceTests.java → core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java

@@ -27,42 +27,44 @@ import org.springframework.security.core.Authentication;
 
 import static org.assertj.core.api.Assertions.assertThat;
 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 AuthorizationManagerMethodAfterAdvice}.
+ * Tests for {@link AuthorizationManagerAfterMethodInterceptor}.
  *
  * @author Evgeniy Cheban
  */
-public class AuthorizationManagerMethodAfterAdviceTests {
+public class AuthorizationManagerAfterMethodInterceptorTests {
 
 	@Test
 	public void instantiateWhenMethodMatcherNullThenException() {
 		AfterMethodAuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(
 				AfterMethodAuthorizationManager.class);
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> new AuthorizationManagerMethodAfterAdvice<>(null, mockAuthorizationManager))
+				.isThrownBy(() -> new AuthorizationManagerAfterMethodInterceptor(null, mockAuthorizationManager))
 				.withMessage("pointcut cannot be null");
 	}
 
 	@Test
 	public void instantiateWhenAuthorizationManagerNullThenException() {
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> new AuthorizationManagerMethodAfterAdvice<>(mock(Pointcut.class), null))
+				.isThrownBy(() -> new AuthorizationManagerAfterMethodInterceptor(mock(Pointcut.class), null))
 				.withMessage("authorizationManager cannot be null");
 	}
 
 	@Test
-	public void beforeWhenMockAuthorizationManagerThenVerifyAndReturnedObject() {
+	public void beforeWhenMockAuthorizationManagerThenVerifyAndReturnedObject() throws Throwable {
 		Supplier<Authentication> authentication = TestAuthentication::authenticatedUser;
 		MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
 		Object returnedObject = new Object();
+		given(mockMethodInvocation.proceed()).willReturn(returnedObject);
 		AfterMethodAuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(
 				AfterMethodAuthorizationManager.class);
-		AuthorizationManagerMethodAfterAdvice<MethodInvocation> advice = new AuthorizationManagerMethodAfterAdvice<>(
-				mock(Pointcut.class), mockAuthorizationManager);
-		Object result = advice.after(authentication, mockMethodInvocation, returnedObject);
+		AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
+				Pointcut.TRUE, mockAuthorizationManager);
+		Object result = advice.invoke(authentication, mockMethodInvocation);
 		assertThat(result).isEqualTo(returnedObject);
 		verify(mockAuthorizationManager).verify(authentication, mockMethodInvocation, returnedObject);
 	}

+ 9 - 8
core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerMethodBeforeAdviceTests.java → core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java

@@ -31,34 +31,35 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 /**
- * Tests for {@link AuthorizationManagerMethodBeforeAdvice}.
+ * Tests for {@link AuthorizationManagerBeforeMethodInterceptor}.
  *
  * @author Evgeniy Cheban
  */
-public class AuthorizationManagerMethodBeforeAdviceTests {
+public class AuthorizationManagerBeforeMethodInterceptorTests {
 
 	@Test
 	public void instantiateWhenMethodMatcherNullThenException() {
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> new AuthorizationManagerMethodBeforeAdvice<>(null, mock(AuthorizationManager.class)))
+				.isThrownBy(
+						() -> new AuthorizationManagerBeforeMethodInterceptor(null, mock(AuthorizationManager.class)))
 				.withMessage("pointcut cannot be null");
 	}
 
 	@Test
 	public void instantiateWhenAuthorizationManagerNullThenException() {
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> new AuthorizationManagerMethodBeforeAdvice<>(mock(Pointcut.class), null))
+				.isThrownBy(() -> new AuthorizationManagerBeforeMethodInterceptor(mock(Pointcut.class), null))
 				.withMessage("authorizationManager cannot be null");
 	}
 
 	@Test
-	public void beforeWhenMockAuthorizationManagerThenVerify() {
+	public void beforeWhenMockAuthorizationManagerThenVerify() throws Throwable {
 		Supplier<Authentication> authentication = TestAuthentication::authenticatedUser;
 		MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
 		AuthorizationManager<MethodInvocation> mockAuthorizationManager = mock(AuthorizationManager.class);
-		AuthorizationManagerMethodBeforeAdvice<MethodInvocation> advice = new AuthorizationManagerMethodBeforeAdvice<>(
-				mock(Pointcut.class), mockAuthorizationManager);
-		advice.before(authentication, mockMethodInvocation);
+		AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
+				Pointcut.TRUE, mockAuthorizationManager);
+		advice.invoke(authentication, mockMethodInvocation);
 		verify(mockAuthorizationManager).verify(authentication, mockMethodInvocation);
 	}
 

+ 167 - 0
core/src/test/java/org/springframework/security/authorization/method/AuthorizationMethodPointcutsTests.java

@@ -0,0 +1,167 @@
+/*
+ * Copyright 2002-2021 the original author or authors.
+ *
+ * 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
+ *
+ *      https://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 org.springframework.security.authorization.method;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.junit.Test;
+
+import org.springframework.aop.Pointcut;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.security.access.prepost.PreAuthorize;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link AuthorizationMethodPointcuts}
+ */
+public class AuthorizationMethodPointcutsTests {
+
+	@Test
+	public void forAnnotationsWhenAnnotationThenClassBasedAnnotationPointcut() {
+		Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
+		assertThat(AopUtils.canApply(preAuthorize, ClassController.class)).isTrue();
+		assertThat(AopUtils.canApply(preAuthorize, NoController.class)).isFalse();
+	}
+
+	@Test
+	public void forAnnotationsWhenAnnotationThenMethodBasedAnnotationPointcut() {
+		Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
+		assertThat(AopUtils.canApply(preAuthorize, MethodController.class)).isTrue();
+	}
+
+	@Test
+	public void forAnnotationsWhenAnnotationThenClassInheritancePointcut() {
+		Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
+		assertThat(AopUtils.canApply(preAuthorize, InterfacedClassController.class)).isTrue();
+	}
+
+	@Test
+	public void forAnnotationsWhenAnnotationThenMethodInheritancePointcut() {
+		Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
+		assertThat(AopUtils.canApply(preAuthorize, InterfacedMethodController.class)).isTrue();
+	}
+
+	@Test
+	public void forAnnotationsWhenAnnotationThenAnnotationClassInheritancePointcut() {
+		Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
+		assertThat(AopUtils.canApply(preAuthorize, InterfacedAnnotationClassController.class)).isTrue();
+	}
+
+	@Test
+	public void forAnnotationsWhenAnnotationThenAnnotationMethodInheritancePointcut() {
+		Pointcut preAuthorize = AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class);
+		assertThat(AopUtils.canApply(preAuthorize, InterfacedAnnotationMethodController.class)).isTrue();
+	}
+
+	@PreAuthorize("hasAuthority('APP')")
+	public static class ClassController {
+
+		String methodOne(String paramOne) {
+			return "value";
+		}
+
+	}
+
+	public static class MethodController {
+
+		@PreAuthorize("hasAuthority('APP')")
+		String methodOne(String paramOne) {
+			return "value";
+		}
+
+	}
+
+	public static class NoController {
+
+		String methodOne(String paramOne) {
+			return "value";
+		}
+
+	}
+
+	@PreAuthorize("hasAuthority('APP')")
+	public interface ClassControllerInterface {
+
+		String methodOne(String paramOne);
+
+	}
+
+	public static class InterfacedClassController implements ClassControllerInterface {
+
+		public String methodOne(String paramOne) {
+			return "value";
+		}
+
+	}
+
+	public interface MethodControllerInterface {
+
+		@PreAuthorize("hasAuthority('APP')")
+		String methodOne(String paramOne);
+
+	}
+
+	public static class InterfacedMethodController implements MethodControllerInterface {
+
+		public String methodOne(String paramOne) {
+			return "value";
+		}
+
+	}
+
+	@Target({ ElementType.METHOD, ElementType.TYPE })
+	@Retention(RetentionPolicy.RUNTIME)
+	@PreAuthorize("hasAuthority('APP')")
+	@interface MyAnnotation {
+
+	}
+
+	@MyAnnotation
+	public interface ClassAnnotationControllerInterface {
+
+		String methodOne(String paramOne);
+
+	}
+
+	public static class InterfacedAnnotationClassController implements ClassAnnotationControllerInterface {
+
+		public String methodOne(String paramOne) {
+			return "value";
+		}
+
+	}
+
+	public interface MethodAnnotationControllerInterface {
+
+		@MyAnnotation
+		String methodOne(String paramOne);
+
+	}
+
+	public static class InterfacedAnnotationMethodController implements MethodAnnotationControllerInterface {
+
+		public String methodOne(String paramOne) {
+			return "value";
+		}
+
+	}
+
+}

+ 0 - 165
core/src/test/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodAfterAdviceTests.java

@@ -1,165 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * 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
- *
- *      https://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 org.springframework.security.authorization.method;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Supplier;
-
-import org.junit.Test;
-
-import org.springframework.aop.MethodMatcher;
-import org.springframework.aop.Pointcut;
-import org.springframework.aop.support.StaticMethodMatcherPointcut;
-import org.springframework.security.access.intercept.method.MockMethodInvocation;
-import org.springframework.security.authentication.TestAuthentication;
-import org.springframework.security.core.Authentication;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests for {@link DelegatingAuthorizationMethodAfterAdvice}.
- *
- * @author Evgeniy Cheban
- */
-public class DelegatingAuthorizationMethodAfterAdviceTests {
-
-	@Test
-	public void methodMatcherWhenNoneMatchesThenNotMatches() throws Exception {
-		List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
-		delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
-					Object returnedObject) {
-				return returnedObject;
-			}
-
-			@Override
-			public Pointcut getPointcut() {
-				return new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				};
-			}
-		});
-		delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
-					Object returnedObject) {
-				return returnedObject;
-			}
-
-			@Override
-			public Pointcut getPointcut() {
-				return new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				};
-			}
-		});
-		DelegatingAuthorizationMethodAfterAdvice advice = new DelegatingAuthorizationMethodAfterAdvice(delegates);
-		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
-		assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
-	}
-
-	@Test
-	public void methodMatcherWhenAnyMatchesThenMatches() throws Exception {
-		List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
-		delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
-					Object returnedObject) {
-				return returnedObject;
-			}
-
-			@Override
-			public Pointcut getPointcut() {
-				return new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				};
-			}
-		});
-		delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
-					Object returnedObject) {
-				return returnedObject;
-			}
-
-			@Override
-			public Pointcut getPointcut() {
-				return Pointcut.TRUE;
-			}
-		});
-		DelegatingAuthorizationMethodAfterAdvice advice = new DelegatingAuthorizationMethodAfterAdvice(delegates);
-		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
-		assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isTrue();
-	}
-
-	@Test
-	public void checkWhenDelegatingAdviceModifiesReturnedObjectThenModifiedReturnedObject() throws Exception {
-		List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
-		delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
-					Object returnedObject) {
-				return returnedObject + "b";
-			}
-
-			@Override
-			public Pointcut getPointcut() {
-				return Pointcut.TRUE;
-			}
-		});
-		delegates.add(new AuthorizationMethodAfterAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Object after(Supplier<Authentication> authentication, MethodAuthorizationContext object,
-					Object returnedObject) {
-				return returnedObject + "c";
-			}
-
-			@Override
-			public Pointcut getPointcut() {
-				return Pointcut.TRUE;
-			}
-		});
-		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
-				"doSomething");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		DelegatingAuthorizationMethodAfterAdvice advice = new DelegatingAuthorizationMethodAfterAdvice(delegates);
-		Object result = advice.after(TestAuthentication::authenticatedUser, methodAuthorizationContext, "a");
-		assertThat(result).isEqualTo("abc");
-	}
-
-	public static class TestClass {
-
-		public String doSomething() {
-			return null;
-		}
-
-	}
-
-}

+ 0 - 164
core/src/test/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodBeforeAdviceTests.java

@@ -1,164 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * 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
- *
- *      https://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 org.springframework.security.authorization.method;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Supplier;
-
-import org.junit.Test;
-
-import org.springframework.aop.MethodMatcher;
-import org.springframework.aop.Pointcut;
-import org.springframework.aop.support.StaticMethodMatcherPointcut;
-import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.access.intercept.method.MockMethodInvocation;
-import org.springframework.security.authentication.TestAuthentication;
-import org.springframework.security.authorization.AuthorizationDecision;
-import org.springframework.security.core.Authentication;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-
-/**
- * Tests for {@link DelegatingAuthorizationMethodBeforeAdvice}.
- *
- * @author Evgeniy Cheban
- */
-public class DelegatingAuthorizationMethodBeforeAdviceTests {
-
-	@Test
-	public void methodMatcherWhenNoneMatchesThenNotMatches() throws Exception {
-		List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
-		delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Pointcut getPointcut() {
-				return new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				};
-			}
-
-			@Override
-			public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
-			}
-		});
-		delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Pointcut getPointcut() {
-				return new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				};
-			}
-
-			@Override
-			public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
-			}
-		});
-		DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
-		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
-		assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
-	}
-
-	@Test
-	public void methodMatcherWhenAnyMatchesThenMatches() throws Exception {
-		List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
-		delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Pointcut getPointcut() {
-				return new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				};
-			}
-
-			@Override
-			public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
-			}
-		});
-		delegates.add(new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
-			@Override
-			public Pointcut getPointcut() {
-				return Pointcut.TRUE;
-			}
-
-			@Override
-			public void before(Supplier<Authentication> authentication, MethodAuthorizationContext object) {
-			}
-		});
-		DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
-		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
-		assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isTrue();
-	}
-
-	@Test
-	public void checkWhenAllGrantsOrAbstainsThenPasses() throws Exception {
-		List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
-		delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(Pointcut.TRUE, (a, o) -> null));
-		delegates.add(
-				new AuthorizationManagerMethodBeforeAdvice<>(Pointcut.TRUE, (a, o) -> new AuthorizationDecision(true)));
-		delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(Pointcut.TRUE, (a, o) -> null));
-		DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
-		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
-				"doSomething");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext);
-	}
-
-	@Test
-	public void checkWhenAnyDeniesThenAccessDeniedException() throws Exception {
-		List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates = new ArrayList<>();
-		delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(Pointcut.TRUE, (a, o) -> null));
-		delegates.add(
-				new AuthorizationManagerMethodBeforeAdvice<>(Pointcut.TRUE, (a, o) -> new AuthorizationDecision(true)));
-		delegates.add(new AuthorizationManagerMethodBeforeAdvice<>(Pointcut.TRUE,
-				(a, o) -> new AuthorizationDecision(false)));
-		DelegatingAuthorizationMethodBeforeAdvice advice = new DelegatingAuthorizationMethodBeforeAdvice(delegates);
-		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
-				"doSomething");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		assertThatExceptionOfType(AccessDeniedException.class)
-				.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
-				.withMessage("Access Denied");
-	}
-
-	@Test
-	public void checkWhenDelegatesEmptyThenFails() {
-		assertThatExceptionOfType(IllegalArgumentException.class)
-				.isThrownBy(() -> new DelegatingAuthorizationMethodBeforeAdvice(Collections.emptyList()));
-	}
-
-	public static class TestClass {
-
-		public void doSomething() {
-
-		}
-
-	}
-
-}

+ 21 - 22
core/src/test/java/org/springframework/security/authorization/method/AuthorizationMethodInterceptorTests.java → core/src/test/java/org/springframework/security/authorization/method/DelegatingAuthorizationMethodInterceptorTests.java

@@ -16,8 +16,10 @@
 
 package org.springframework.security.authorization.method;
 
+import java.util.Arrays;
 import java.util.function.Supplier;
 
+import org.aopalliance.intercept.MethodInvocation;
 import org.junit.After;
 import org.junit.Test;
 
@@ -32,18 +34,17 @@ import org.springframework.security.core.context.SecurityContextImpl;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoInteractions;
 
 /**
- * Tests for {@link AuthorizationMethodInterceptor}.
+ * Tests for {@link DelegatingAuthorizationMethodInterceptor}.
  *
  * @author Evgeniy Cheban
  */
-public class AuthorizationMethodInterceptorTests {
+public class DelegatingAuthorizationMethodInterceptorTests {
 
 	@After
 	public void tearDown() {
@@ -56,41 +57,39 @@ public class AuthorizationMethodInterceptorTests {
 		SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingString");
-		AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> mockBeforeAdvice = mock(
-				AuthorizationMethodBeforeAdvice.class);
-		AuthorizationMethodAfterAdvice<MethodAuthorizationContext> mockAfterAdvice = mock(
-				AuthorizationMethodAfterAdvice.class);
-		given(mockAfterAdvice.after(any(), any(MethodAuthorizationContext.class), eq(null))).willReturn("abc");
-		AuthorizationMethodInterceptor interceptor = new AuthorizationMethodInterceptor(mockBeforeAdvice,
-				mockAfterAdvice);
-		Object result = interceptor.invoke(mockMethodInvocation);
+		AuthorizationMethodInterceptor interceptor = mock(AuthorizationMethodInterceptor.class);
+		given(interceptor.getPointcut()).willReturn(Pointcut.TRUE);
+		given(interceptor.invoke(any(), any(AuthorizationMethodInvocation.class))).willReturn("abc");
+		DelegatingAuthorizationMethodInterceptor chain = new DelegatingAuthorizationMethodInterceptor(
+				Arrays.asList(interceptor));
+		Object result = chain.invoke(mockMethodInvocation);
 		assertThat(result).isEqualTo("abc");
-		verify(mockAfterAdvice).after(any(), any(MethodAuthorizationContext.class), eq(null));
+		verify(interceptor).invoke(any(), any(AuthorizationMethodInvocation.class));
 	}
 
 	@Test
-	public void invokeWhenNotAuthenticatedThenAuthenticationCredentialsNotFoundException() throws Exception {
+	public void invokeWhenNotAuthenticatedThenAuthenticationCredentialsNotFoundException() throws Throwable {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingString");
-		AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> beforeAdvice = new AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>() {
+		AuthorizationMethodInterceptor first = new AuthorizationMethodInterceptor() {
 			@Override
 			public Pointcut getPointcut() {
 				return Pointcut.TRUE;
 			}
 
 			@Override
-			public void before(Supplier<Authentication> authentication,
-					MethodAuthorizationContext methodAuthorizationContext) {
-				authentication.get();
+			public Object invoke(Supplier<Authentication> authentication, MethodInvocation mi) {
+				return authentication.get();
 			}
 		};
-		AuthorizationMethodAfterAdvice<MethodAuthorizationContext> mockAfterAdvice = mock(
-				AuthorizationMethodAfterAdvice.class);
-		AuthorizationMethodInterceptor interceptor = new AuthorizationMethodInterceptor(beforeAdvice, mockAfterAdvice);
+		AuthorizationMethodInterceptor second = mock(AuthorizationMethodInterceptor.class);
+		given(second.getPointcut()).willReturn(Pointcut.TRUE);
+		DelegatingAuthorizationMethodInterceptor interceptor = new DelegatingAuthorizationMethodInterceptor(
+				Arrays.asList(first, second));
 		assertThatExceptionOfType(AuthenticationCredentialsNotFoundException.class)
 				.isThrownBy(() -> interceptor.invoke(mockMethodInvocation))
 				.withMessage("An Authentication object was not found in the SecurityContext");
-		verifyNoInteractions(mockAfterAdvice);
+		verify(second, times(0)).invoke(any(), any());
 	}
 
 	public static class TestClass {

+ 25 - 29
core/src/test/java/org/springframework/security/authorization/method/Jsr250AuthorizationManagerTests.java

@@ -16,6 +16,7 @@
 
 package org.springframework.security.authorization.method;
 
+import java.util.Collections;
 import java.util.function.Supplier;
 
 import javax.annotation.security.DenyAll;
@@ -62,64 +63,59 @@ public class Jsr250AuthorizationManagerTests {
 
 	@Test
 	public void checkDoSomethingWhenNoJsr250AnnotationsThenNullDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomething");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNull();
 	}
 
 	@Test
 	public void checkPermitAllRolesAllowedAdminWhenRoleUserThenGrantedDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"permitAllRolesAllowedAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
 
 	@Test
 	public void checkDenyAllRolesAllowedAdminWhenRoleAdminThenDeniedDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"denyAllRolesAllowedAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isFalse();
 	}
 
 	@Test
 	public void checkRolesAllowedUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"rolesAllowedUserOrAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
 
 	@Test
 	public void checkRolesAllowedUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"rolesAllowedUserOrAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
@@ -128,12 +124,12 @@ public class Jsr250AuthorizationManagerTests {
 	public void checkRolesAllowedUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
 		Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
 				"ROLE_ANONYMOUS");
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"rolesAllowedUserOrAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
-		AuthorizationDecision decision = manager.check(authentication, methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(authentication, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isFalse();
 	}

+ 15 - 20
core/src/test/java/org/springframework/security/authorization/method/PostAuthorizeAuthorizationManagerTests.java

@@ -58,11 +58,10 @@ public class PostAuthorizeAuthorizationManagerTests {
 	public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomething", new Class[] {}, new Object[] {});
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext, null);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, null);
 		assertThat(decision).isNull();
 	}
 
@@ -70,11 +69,10 @@ public class PostAuthorizeAuthorizationManagerTests {
 	public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext, null);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, null);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
@@ -83,11 +81,10 @@ public class PostAuthorizeAuthorizationManagerTests {
 	public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext, null);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, null);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isFalse();
 	}
@@ -97,11 +94,10 @@ public class PostAuthorizeAuthorizationManagerTests {
 		List<String> list = Arrays.asList("grant", "deny");
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingList", new Class[] { List.class }, new Object[] { list });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext, list);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, list);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
@@ -111,11 +107,10 @@ public class PostAuthorizeAuthorizationManagerTests {
 		List<String> list = Collections.singletonList("deny");
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingList", new Class[] { List.class }, new Object[] { list });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext, list);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation, list);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isFalse();
 	}

+ 28 - 26
core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodAfterAdviceTests.java → core/src/test/java/org/springframework/security/authorization/method/PostFilterAuthorizationMethodInterceptorTests.java

@@ -16,14 +16,12 @@
 
 package org.springframework.security.authorization.method;
 
-import java.lang.reflect.Method;
+import java.util.Collections;
 
 import org.assertj.core.api.InstanceOfAssertFactories;
 import org.junit.Test;
 
 import org.springframework.aop.MethodMatcher;
-import org.springframework.aop.Pointcut;
-import org.springframework.aop.support.StaticMethodMatcherPointcut;
 import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
 import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
 import org.springframework.security.access.intercept.method.MockMethodInvocation;
@@ -34,43 +32,38 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 
 /**
- * Tests for {@link PostFilterAuthorizationMethodAfterAdvice}.
+ * Tests for {@link PostFilterAuthorizationMethodInterceptor}.
  *
  * @author Evgeniy Cheban
  */
-public class PostFilterAuthorizationMethodAfterAdviceTests {
+public class PostFilterAuthorizationMethodInterceptorTests {
 
 	@Test
 	public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
 		MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
-		PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice(Pointcut.TRUE);
+		PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
 		advice.setExpressionHandler(expressionHandler);
 		assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
 	}
 
 	@Test
 	public void setExpressionHandlerWhenNullThenException() {
-		PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice(Pointcut.TRUE);
+		PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
 		assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
 				.withMessage("expressionHandler cannot be null");
 	}
 
 	@Test
 	public void methodMatcherWhenMethodHasNotPostFilterAnnotationThenNotMatches() throws Exception {
-		PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice(
-				new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				});
+		PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
 		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
-		assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
+		assertThat(methodMatcher.matches(NoPostFilterClass.class.getMethod("doSomething"), NoPostFilterClass.class))
+				.isFalse();
 	}
 
 	@Test
 	public void methodMatcherWhenMethodHasPostFilterAnnotationThenMatches() throws Exception {
-		PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice(Pointcut.TRUE);
+		PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
 		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
 		assertThat(
 				methodMatcher.matches(TestClass.class.getMethod("doSomethingArray", String[].class), TestClass.class))
@@ -78,24 +71,25 @@ public class PostFilterAuthorizationMethodAfterAdviceTests {
 	}
 
 	@Test
-	public void afterWhenArrayNotNullThenFilteredArray() throws Exception {
+	public void afterWhenArrayNotNullThenFilteredArray() throws Throwable {
 		String[] array = { "john", "bob" };
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
-				"doSomethingArrayClassLevel", new Class[] { String[].class }, new Object[] { array });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PostFilterAuthorizationMethodAfterAdvice advice = new PostFilterAuthorizationMethodAfterAdvice(Pointcut.TRUE);
-		Object result = advice.after(TestAuthentication::authenticatedUser, methodAuthorizationContext, array);
+				"doSomethingArrayClassLevel", new Class[] { String[].class }, new Object[] { array }) {
+			@Override
+			public Object proceed() {
+				return array;
+			}
+		};
+		PostFilterAuthorizationMethodInterceptor advice = new PostFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
+		Object result = advice.invoke(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(result).asInstanceOf(InstanceOfAssertFactories.array(String[].class)).containsOnly("john");
 	}
 
 	@PostFilter("filterObject == 'john'")
 	public static class TestClass {
 
-		public void doSomething() {
-
-		}
-
 		@PostFilter("filterObject == 'john'")
 		public String[] doSomethingArray(String[] array) {
 			return array;
@@ -107,4 +101,12 @@ public class PostFilterAuthorizationMethodAfterAdviceTests {
 
 	}
 
+	public static class NoPostFilterClass {
+
+		public void doSomething() {
+
+		}
+
+	}
+
 }

+ 11 - 12
core/src/test/java/org/springframework/security/authorization/method/PreAuthorizeAuthorizationManagerTests.java

@@ -16,6 +16,8 @@
 
 package org.springframework.security.authorization.method;
 
+import java.util.Collections;
+
 import org.junit.Test;
 
 import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
@@ -54,11 +56,10 @@ public class PreAuthorizeAuthorizationManagerTests {
 	public void checkDoSomethingWhenNoPostAuthorizeAnnotationThenNullDecision() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomething", new Class[] {}, new Object[] {});
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNull();
 	}
 
@@ -66,11 +67,10 @@ public class PreAuthorizeAuthorizationManagerTests {
 	public void checkDoSomethingStringWhenArgIsGrantThenGrantedDecision() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingString", new Class[] { String.class }, new Object[] { "grant" });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
@@ -79,11 +79,10 @@ public class PreAuthorizeAuthorizationManagerTests {
 	public void checkDoSomethingStringWhenArgIsNotGrantThenDeniedDecision() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingString", new Class[] { String.class }, new Object[] { "deny" });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isFalse();
 	}

+ 47 - 52
core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodBeforeAdviceTests.java → core/src/test/java/org/springframework/security/authorization/method/PreFilterAuthorizationMethodInterceptorTests.java

@@ -16,15 +16,13 @@
 
 package org.springframework.security.authorization.method;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import org.junit.Test;
 
 import org.springframework.aop.MethodMatcher;
-import org.springframework.aop.Pointcut;
-import org.springframework.aop.support.StaticMethodMatcherPointcut;
 import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
 import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
 import org.springframework.security.access.intercept.method.MockMethodInvocation;
@@ -36,43 +34,38 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
 
 /**
- * Tests for {@link PreFilterAuthorizationMethodBeforeAdvice}.
+ * Tests for {@link PreFilterAuthorizationMethodInterceptor}.
  *
  * @author Evgeniy Cheban
  */
-public class PreFilterAuthorizationMethodBeforeAdviceTests {
+public class PreFilterAuthorizationMethodInterceptorTests {
 
 	@Test
 	public void setExpressionHandlerWhenNotNullThenSetsExpressionHandler() {
 		MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
 		advice.setExpressionHandler(expressionHandler);
 		assertThat(advice).extracting("expressionHandler").isEqualTo(expressionHandler);
 	}
 
 	@Test
 	public void setExpressionHandlerWhenNullThenException() {
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
 		assertThatIllegalArgumentException().isThrownBy(() -> advice.setExpressionHandler(null))
 				.withMessage("expressionHandler cannot be null");
 	}
 
 	@Test
 	public void methodMatcherWhenMethodHasNotPreFilterAnnotationThenNotMatches() throws Exception {
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(
-				new StaticMethodMatcherPointcut() {
-					@Override
-					public boolean matches(Method method, Class<?> targetClass) {
-						return false;
-					}
-				});
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
 		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
-		assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomething"), TestClass.class)).isFalse();
+		assertThat(methodMatcher.matches(NoPreFilterClass.class.getMethod("doSomething"), NoPreFilterClass.class))
+				.isFalse();
 	}
 
 	@Test
 	public void methodMatcherWhenMethodHasPreFilterAnnotationThenMatches() throws Exception {
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
 		MethodMatcher methodMatcher = advice.getPointcut().getMethodMatcher();
 		assertThat(methodMatcher.matches(TestClass.class.getMethod("doSomethingListFilterTargetMatch", List.class),
 				TestClass.class)).isTrue();
@@ -82,12 +75,11 @@ public class PreFilterAuthorizationMethodBeforeAdviceTests {
 	public void findFilterTargetWhenNameProvidedAndNotMatchThenException() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingListFilterTargetNotMatch", new Class[] { List.class }, new Object[] { new ArrayList<>() });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
-				.withMessage(
+				.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation)).withMessage(
 						"Filter target was null, or no argument with name 'filterTargetNotMatch' found in method.");
 	}
 
@@ -95,25 +87,25 @@ public class PreFilterAuthorizationMethodBeforeAdviceTests {
 	public void findFilterTargetWhenNameProvidedAndMatchAndNullThenException() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { null });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
+				.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation))
 				.withMessage("Filter target was null, or no argument with name 'list' found in method.");
 	}
 
 	@Test
-	public void findFilterTargetWhenNameProvidedAndMatchAndNotNullThenFiltersList() throws Exception {
+	public void findFilterTargetWhenNameProvidedAndMatchAndNotNullThenFiltersList() throws Throwable {
 		List<String> list = new ArrayList<>();
 		list.add("john");
 		list.add("bob");
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingListFilterTargetMatch", new Class[] { List.class }, new Object[] { list });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
-		advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
+		advice.invoke(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(list).hasSize(1);
 		assertThat(list.get(0)).isEqualTo("john");
 	}
@@ -122,25 +114,25 @@ public class PreFilterAuthorizationMethodBeforeAdviceTests {
 	public void findFilterTargetWhenNameNotProvidedAndSingleArgListNullThenException() throws Exception {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { null });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		assertThatIllegalArgumentException()
-				.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
+				.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation))
 				.withMessage("Filter target was null. Make sure you passing the correct value in the method argument.");
 	}
 
 	@Test
-	public void findFilterTargetWhenNameNotProvidedAndSingleArgListThenFiltersList() throws Exception {
+	public void findFilterTargetWhenNameNotProvidedAndSingleArgListThenFiltersList() throws Throwable {
 		List<String> list = new ArrayList<>();
 		list.add("john");
 		list.add("bob");
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingListFilterTargetNotProvided", new Class[] { List.class }, new Object[] { list });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
-		advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
+		advice.invoke(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(list).hasSize(1);
 		assertThat(list.get(0)).isEqualTo("john");
 	}
@@ -150,12 +142,11 @@ public class PreFilterAuthorizationMethodBeforeAdviceTests {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingArrayFilterTargetNotProvided", new Class[] { String[].class },
 				new Object[] { new String[] {} });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		assertThatIllegalStateException()
-				.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
-				.withMessage(
+				.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation)).withMessage(
 						"Pre-filtering on array types is not supported. Using a Collection will solve this problem.");
 	}
 
@@ -164,21 +155,17 @@ public class PreFilterAuthorizationMethodBeforeAdviceTests {
 		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomethingTwoArgsFilterTargetNotProvided", new Class[] { String.class, List.class },
 				new Object[] { "", new ArrayList<>() });
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(mockMethodInvocation,
-				TestClass.class);
-		PreFilterAuthorizationMethodBeforeAdvice advice = new PreFilterAuthorizationMethodBeforeAdvice(Pointcut.TRUE);
+		PreFilterAuthorizationMethodInterceptor advice = new PreFilterAuthorizationMethodInterceptor();
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		assertThatIllegalStateException()
-				.isThrownBy(() -> advice.before(TestAuthentication::authenticatedUser, methodAuthorizationContext))
+				.isThrownBy(() -> advice.invoke(TestAuthentication::authenticatedUser, methodInvocation))
 				.withMessage("Unable to determine the method argument for filtering. Specify the filter target.");
 	}
 
 	@PreFilter("filterObject == 'john'")
 	public static class TestClass {
 
-		public void doSomething() {
-
-		}
-
 		@PreFilter(value = "filterObject == 'john'", filterTarget = "filterTargetNotMatch")
 		public List<String> doSomethingListFilterTargetNotMatch(List<String> list) {
 			return list;
@@ -205,4 +192,12 @@ public class PreFilterAuthorizationMethodBeforeAdviceTests {
 
 	}
 
+	public static class NoPreFilterClass {
+
+		public void doSomething() {
+
+		}
+
+	}
+
 }

+ 17 - 19
core/src/test/java/org/springframework/security/authorization/method/SecuredAuthorizationManagerTests.java

@@ -16,6 +16,7 @@
 
 package org.springframework.security.authorization.method;
 
+import java.util.Collections;
 import java.util.function.Supplier;
 
 import org.junit.Test;
@@ -38,38 +39,35 @@ public class SecuredAuthorizationManagerTests {
 
 	@Test
 	public void checkDoSomethingWhenNoSecuredAnnotationThenNullDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"doSomething");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNull();
 	}
 
 	@Test
 	public void checkSecuredUserOrAdminWhenRoleUserThenGrantedDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"securedUserOrAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedUser, mockMethodInvocation, Collections.emptyList());
 		SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedUser, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
 
 	@Test
 	public void checkSecuredUserOrAdminWhenRoleAdminThenGrantedDecision() throws Exception {
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"securedUserOrAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(
+				TestAuthentication::authenticatedAdmin, mockMethodInvocation, Collections.emptyList());
 		SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
-		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin,
-				methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(TestAuthentication::authenticatedAdmin, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isTrue();
 	}
@@ -78,12 +76,12 @@ public class SecuredAuthorizationManagerTests {
 	public void checkSecuredUserOrAdminWhenRoleAnonymousThenDeniedDecision() throws Exception {
 		Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password",
 				"ROLE_ANONYMOUS");
-		MockMethodInvocation methodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
+		MockMethodInvocation mockMethodInvocation = new MockMethodInvocation(new TestClass(), TestClass.class,
 				"securedUserOrAdmin");
-		MethodAuthorizationContext methodAuthorizationContext = new MethodAuthorizationContext(methodInvocation,
-				TestClass.class);
+		AuthorizationMethodInvocation methodInvocation = new AuthorizationMethodInvocation(authentication,
+				mockMethodInvocation, Collections.emptyList());
 		SecuredAuthorizationManager manager = new SecuredAuthorizationManager();
-		AuthorizationDecision decision = manager.check(authentication, methodAuthorizationContext);
+		AuthorizationDecision decision = manager.check(authentication, methodInvocation);
 		assertThat(decision).isNotNull();
 		assertThat(decision.isGranted()).isFalse();
 	}

+ 46 - 30
docs/manual/src/docs/asciidoc/_includes/servlet/authorization/method-security.adoc

@@ -25,7 +25,7 @@ public class MethodSecurityConfig {
 
 Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly.
 Spring Security's native annotatino support defines a set of attributes for the method.
-These will be passed to the `AuthorizationMethodInterceptor` for it to make the actual decision:
+These will be passed to the `DefaultAuthorizationMethodInterceptorChain` for it to make the actual decision:
 
 [source,java]
 ----
@@ -100,41 +100,59 @@ If that authorization denies access, the method is not invoked and an `AccessDen
 After-method authorization is performed after the method is invoked, but before the method returns to the caller.
 If that authorization denies access, the value is not returned and an `AccessDeniedException` is thrown
 
-You can customize before-method authorization by publishing your own `AuthorizationMethodBeforeAdvice` bean, which includes your custom authorization manager as well as the `Pointcut` that describes when your manager should be used.
+To recreate what Spring Security does by default, you would publish the following bean:
 
-For example, you may want to apply a default authorization rule to all methods in your service layer.
-To do this, you'll supply the pointcut as well as the rule, like so:
+[source,java]
+----
+@Bean
+public List<AuthorizationMethodInterceptor> methodSecurity() {
+	return new DelegatingAuthorizationMethodInterceptor(
+			new PreFilterAuthorizationMethodInterceptor(), // before-method
+            AuthorizationMethodInterceptors.preAuthorize(), // before-method
+            new PostFilterAuthorizationMethodInterceptor(), // after-method
+            AuthorizationMethodInterceptors.postAuthorize() // after-method
+	);
+}
+----
+
+[NOTE]
+Keep in mind that publishing a list of `AuthorizationMethodInterceptor`s will completely replace any Spring Security defaults.
+
+Interceptors are invoked in the order that they are declared.
+
+You may want to only support `@PreAuthorize` in your application, in which case you can do the following:
 
 [source,java]
 ----
 @Bean
-public AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> authorizationMethodBeforeAdvice() {
-	JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut();
-	pattern.setPattern("org.mycompany.myapp.service.*");
-	AuthorizationManager<MethodAuthorizationContext> rule = AuthorityAuthorizationManager.isAuthenticated();
-	return new AuthorizationManagerMethodBeforeAdvice(pattern, rule);
+public AuthorizationMethodInterceptor methodSecurity() {
+	return AuthorizationMethodInterceptors.preAuthorize();
 }
 ----
 
-This will replace any default before advice that Spring Security provides.
-To use your custom rule as well as Spring Security's `@PreAuthorize` authorization support, you can do:
+Or, you may have a custom before-method `AuthorizationManager` that you want to add to the list.
+
+In this case, you will need to tell Spring Security both the `AuthorizationManager` and to which methods and classes your authorization manager applies.
+
+Spring Security integrates with Spring AOP to achieve this.
+Thus, you can configure Spring Security to support `@PreAuthorize`, `@PostAuthorize`, and your own `AuthorizationManager` like so:
 
 [source,java]
 ----
 @Bean
-public AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> authorizationMethodBeforeAdvice() {
+public AuthorizationMethodInterceptor methodSecurity() {
 	JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut();
 	pattern.setPattern("org.mycompany.myapp.service.*");
-	AuthorizationManager rule = AuthorityAuthorizationManager.isAuthenticated();
-	AuthorizationMethodBeforeAdvice custom = new AuthorizationManagerMethodBeforeAdvice(pattern, rule);
-	AuthorizationMethodBeforeAdvice pre = new AuthorizationMethodBeforeAdvice(
-			AuthorizationMethodPointcuts.forAnnotations(PreAuthorize.class),
-			new PreAuthorizeAuthorizationManager());
-	return new DelegatingAuthorizationManagerBeforeAdvice(custom, pre);
+	AuthorizationManager<MethodInvocation> rule = AuthorityAuthorizationManager.isAuthenticated();
+	return new DelegatingAuthorizationMethodInterceptor(
+			AuthorizationMethodInterceptors.preAuthorize(),
+            new AuthorizationManagerBeforeMethodInterceptor(pattern, rule),
+            AuthorizationMethodInterceptors.postAuthorize()
+	);
 }
 ----
 
-The same can be done for after-method authorization.
+The same can be done for after-method authorization and `AfterMethodAuthorizationManager`.
 After-method authorization is generally concerned with analysing the return value to verify access.
 
 For example, you might have a method that confirms that the account requested actually belongs to the logged-in user like so:
@@ -149,22 +167,20 @@ public interface BankService {
 }
 ----
 
-You can supply your own `AuthorizationMethodAfterAdvice` to customize how access to the return value is evaluated.
+You can supply your own `AuthorizationMethodInterceptor` to customize how access to the return value is evaluated.
 
-For example, you can give special access to a given role in your system, like so:
+For example, instead of embedding a great deal of logic into the `@PostAuthorize` SpEL expression, you may want to wire your own `@Bean`.
+In that case, you can configure it like so:
 
 [source,java]
 ----
 @Bean
-public AuthorizationMethodAfterAdvice<MethodAuthorizationContext> authorizationMethodAfterAdvice() {
-	JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut();
-	pattern.setPattern("org.mycompany.myapp.service.*");
-	AuthorizationManager<MethodAuthorizationContext> rule = AuthorityAuthorizationManager.hasRole("TELLER");
-	AuthorizationMethodBeforeAdvice custom = new AuthorizationManagerMethodBeforeAdvice(pattern, rule);
-	AuthorizationMethodBeforeAdvice post = new AuthorizationManagerMethodBeforeAdvice(
-			AuthorizationMethodPointcuts.forAnnotations(PostAuthorize.class),
-			new PostAuthorizeAuthorizationManager());
-	return new DelegatingAuthorizationManagerBeforeAdvice(custom, post);
+public AuthorizationMethodInterceptor methodSecurity
+		(AfterMethodAuthorizationManager<MethodInvocation> rules) {
+	AnnotationMethodMatcher pattern = new AnnotationMethodMatcher(MySecurityAnnotation.class);
+	return new DelegatingAuthorizationMethodInterceptor(
+			AuthorizationMethodInterceptors.preAuthorize(),
+			new AuthorizationManagerAfterMethodInterceptor(pattern, rules));
 }
 ----