Sfoglia il codice sorgente

Add order offset to @EnableMethodSecurity

Closes gh-13214
Yan Kardziyaka 1 anno fa
parent
commit
99218db84a

+ 11 - 1
config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableMethodSecurity.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -87,4 +87,14 @@ public @interface EnableMethodSecurity {
 	 */
 	AdviceMode mode() default AdviceMode.PROXY;
 
+	/**
+	 * Indicate additional offset in the ordering of the execution of the security
+	 * interceptors when multiple advices are applied at a specific joinpoint. I.e.,
+	 * precedence of each security interceptor enabled by this annotation will be
+	 * calculated as sum of its default precedence and offset. The default is 0.
+	 * @return the offset in the order the security advisor should be applied
+	 * @since 6.3
+	 */
+	int offset() default 0;
+
 }

+ 14 - 2
config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MethodSecurityConfiguration.java

@@ -24,7 +24,9 @@ import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportAware;
 import org.springframework.context.annotation.Role;
+import org.springframework.core.type.AnnotationMetadata;
 import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
@@ -45,14 +47,17 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
  */
 @Configuration(proxyBeanMethods = false)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
-final class Jsr250MethodSecurityConfiguration {
+final class Jsr250MethodSecurityConfiguration implements ImportAware {
+
+	private int interceptorOrderOffset;
 
 	@Bean
 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 	static MethodInterceptor jsr250AuthorizationMethodInterceptor(
 			ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
 			ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
-			ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider) {
+			ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
+			Jsr250MethodSecurityConfiguration configuration) {
 		Jsr250AuthorizationManager jsr250 = new Jsr250AuthorizationManager();
 		AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
 		RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
@@ -65,8 +70,15 @@ final class Jsr250MethodSecurityConfiguration {
 				registryProvider, jsr250);
 		AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
 			.jsr250(manager);
+		interceptor.setOrder(interceptor.getOrder() + configuration.interceptorOrderOffset);
 		interceptor.setSecurityContextHolderStrategy(strategy);
 		return interceptor;
 	}
 
+	@Override
+	public void setImportMetadata(AnnotationMetadata importMetadata) {
+		EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
+		this.interceptorOrderOffset = annotation.offset();
+	}
+
 }

+ 21 - 5
config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java

@@ -27,7 +27,9 @@ import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportAware;
 import org.springframework.context.annotation.Role;
+import org.springframework.core.type.AnnotationMetadata;
 import org.springframework.expression.EvaluationContext;
 import org.springframework.expression.Expression;
 import org.springframework.expression.ExpressionParser;
@@ -58,7 +60,9 @@ import org.springframework.util.function.SingletonSupplier;
  */
 @Configuration(proxyBeanMethods = false)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
-final class PrePostMethodSecurityConfiguration {
+final class PrePostMethodSecurityConfiguration implements ImportAware {
+
+	private int interceptorOrderOffset;
 
 	@Bean
 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@@ -66,8 +70,10 @@ final class PrePostMethodSecurityConfiguration {
 			ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
 			ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
 			ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
-			ObjectProvider<RoleHierarchy> roleHierarchyProvider, ApplicationContext context) {
+			ObjectProvider<RoleHierarchy> roleHierarchyProvider, PrePostMethodSecurityConfiguration configuration,
+			ApplicationContext context) {
 		PreFilterAuthorizationMethodInterceptor preFilter = new PreFilterAuthorizationMethodInterceptor();
+		preFilter.setOrder(preFilter.getOrder() + configuration.interceptorOrderOffset);
 		strategyProvider.ifAvailable(preFilter::setSecurityContextHolderStrategy);
 		preFilter.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
 				defaultsProvider, roleHierarchyProvider, context));
@@ -82,12 +88,13 @@ final class PrePostMethodSecurityConfiguration {
 			ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
 			ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
 			ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
-			ApplicationContext context) {
+			PrePostMethodSecurityConfiguration configuration, ApplicationContext context) {
 		PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
 		manager.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
 				defaultsProvider, roleHierarchyProvider, context));
 		AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor
 			.preAuthorize(manager(manager, registryProvider));
+		preAuthorize.setOrder(preAuthorize.getOrder() + configuration.interceptorOrderOffset);
 		strategyProvider.ifAvailable(preAuthorize::setSecurityContextHolderStrategy);
 		eventPublisherProvider.ifAvailable(preAuthorize::setAuthorizationEventPublisher);
 		return preAuthorize;
@@ -101,12 +108,13 @@ final class PrePostMethodSecurityConfiguration {
 			ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
 			ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
 			ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
-			ApplicationContext context) {
+			PrePostMethodSecurityConfiguration configuration, ApplicationContext context) {
 		PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
 		manager.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
 				defaultsProvider, roleHierarchyProvider, context));
 		AuthorizationManagerAfterMethodInterceptor postAuthorize = AuthorizationManagerAfterMethodInterceptor
 			.postAuthorize(manager(manager, registryProvider));
+		postAuthorize.setOrder(postAuthorize.getOrder() + configuration.interceptorOrderOffset);
 		strategyProvider.ifAvailable(postAuthorize::setSecurityContextHolderStrategy);
 		eventPublisherProvider.ifAvailable(postAuthorize::setAuthorizationEventPublisher);
 		return postAuthorize;
@@ -118,8 +126,10 @@ final class PrePostMethodSecurityConfiguration {
 			ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
 			ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
 			ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
-			ObjectProvider<RoleHierarchy> roleHierarchyProvider, ApplicationContext context) {
+			ObjectProvider<RoleHierarchy> roleHierarchyProvider, PrePostMethodSecurityConfiguration configuration,
+			ApplicationContext context) {
 		PostFilterAuthorizationMethodInterceptor postFilter = new PostFilterAuthorizationMethodInterceptor();
+		postFilter.setOrder(postFilter.getOrder() + configuration.interceptorOrderOffset);
 		strategyProvider.ifAvailable(postFilter::setSecurityContextHolderStrategy);
 		postFilter.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
 				defaultsProvider, roleHierarchyProvider, context));
@@ -142,6 +152,12 @@ final class PrePostMethodSecurityConfiguration {
 		return new DeferringObservationAuthorizationManager<>(registryProvider, delegate);
 	}
 
+	@Override
+	public void setImportMetadata(AnnotationMetadata importMetadata) {
+		EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
+		this.interceptorOrderOffset = annotation.offset();
+	}
+
 	private static final class DeferringMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {
 
 		private final Supplier<MethodSecurityExpressionHandler> expressionHandler;

+ 14 - 2
config/src/main/java/org/springframework/security/config/annotation/method/configuration/SecuredMethodSecurityConfiguration.java

@@ -24,7 +24,9 @@ import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportAware;
 import org.springframework.context.annotation.Role;
+import org.springframework.core.type.AnnotationMetadata;
 import org.springframework.security.access.annotation.Secured;
 import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
@@ -45,13 +47,16 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
  */
 @Configuration(proxyBeanMethods = false)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
-final class SecuredMethodSecurityConfiguration {
+final class SecuredMethodSecurityConfiguration implements ImportAware {
+
+	private int interceptorOrderOffset;
 
 	@Bean
 	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 	static MethodInterceptor securedAuthorizationMethodInterceptor(
 			ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
-			ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider) {
+			ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
+			SecuredMethodSecurityConfiguration configuration) {
 		SecuredAuthorizationManager secured = new SecuredAuthorizationManager();
 		AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
 		RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
@@ -63,8 +68,15 @@ final class SecuredMethodSecurityConfiguration {
 				registryProvider, secured);
 		AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
 			.secured(manager);
+		interceptor.setOrder(interceptor.getOrder() + configuration.interceptorOrderOffset);
 		interceptor.setSecurityContextHolderStrategy(strategy);
 		return interceptor;
 	}
 
+	@Override
+	public void setImportMetadata(AnnotationMetadata importMetadata) {
+		EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
+		this.interceptorOrderOffset = annotation.offset();
+	}
+
 }

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

@@ -96,6 +96,14 @@ public interface MethodSecurityService {
 	@PostAuthorize("returnObject.size == 2")
 	List<String> manyAnnotations(List<String> array);
 
+	@PreFilter("filterObject != 'DropOnPreFilter'")
+	@PreAuthorize("#list.remove('DropOnPreAuthorize')")
+	@Secured("ROLE_SECURED")
+	@RolesAllowed("JSR250")
+	@PostAuthorize("#list.remove('DropOnPostAuthorize')")
+	@PostFilter("filterObject != 'DropOnPostFilter'")
+	List<String> allAnnotations(List<String> list);
+
 	@RequireUserRole
 	@RequireAdminRole
 	void repeatedAnnotations();

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

@@ -117,6 +117,11 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
 		return object;
 	}
 
+	@Override
+	public List<String> allAnnotations(List<String> list) {
+		return null;
+	}
+
 	@Override
 	public void repeatedAnnotations() {
 	}

+ 207 - 0
config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java

@@ -36,6 +36,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.context.annotation.AdviceMode;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
 import org.springframework.context.annotation.Role;
 import org.springframework.core.annotation.AnnotationConfigurationException;
 import org.springframework.security.access.AccessDeniedException;
@@ -467,10 +468,115 @@ public class PrePostMethodSecurityConfigurationTests {
 		this.methodSecurityService.jsr250RolesAllowedUser();
 	}
 
+	@Test
+	public void allAnnotationsWhenAdviceBeforeOffsetPreFilterThenReturnsFilteredList() {
+		this.spring.register(ReturnBeforeOffsetPreFilterConfig.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		List<String> filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list));
+		assertThat(filtered).hasSize(5);
+		assertThat(filtered).containsExactly("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+	}
+
+	@Test
+	public void allAnnotationsWhenAdviceBeforeOffsetPreAuthorizeThenReturnsFilteredList() {
+		this.spring.register(ReturnBeforeOffsetPreAuthorizeConfig.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		List<String> filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list));
+		assertThat(filtered).hasSize(4);
+		assertThat(filtered).containsExactly("DropOnPreAuthorize", "DropOnPostAuthorize", "DropOnPostFilter",
+				"DoNotDrop");
+	}
+
+	@Test
+	public void allAnnotationsWhenAdviceBeforeOffsetSecuredThenReturnsFilteredList() {
+		this.spring.register(ReturnBeforeOffsetSecuredConfig.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		List<String> filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list));
+		assertThat(filtered).hasSize(3);
+		assertThat(filtered).containsExactly("DropOnPostAuthorize", "DropOnPostFilter", "DoNotDrop");
+	}
+
+	@Test
+	@WithMockUser
+	public void allAnnotationsWhenAdviceBeforeOffsetJsr250WithInsufficientRolesThenFails() {
+		this.spring.register(ReturnBeforeOffsetJsr250Config.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		assertThatExceptionOfType(AccessDeniedException.class)
+			.isThrownBy(() -> this.methodSecurityService.allAnnotations(new ArrayList<>(list)));
+	}
+
+	@Test
+	@WithMockUser(roles = "SECURED")
+	public void allAnnotationsWhenAdviceBeforeOffsetJsr250ThenReturnsFilteredList() {
+		this.spring.register(ReturnBeforeOffsetJsr250Config.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		List<String> filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list));
+		assertThat(filtered).hasSize(3);
+		assertThat(filtered).containsExactly("DropOnPostAuthorize", "DropOnPostFilter", "DoNotDrop");
+	}
+
+	@Test
+	@WithMockUser(roles = { "SECURED" })
+	public void allAnnotationsWhenAdviceBeforeOffsetPostAuthorizeWithInsufficientRolesThenFails() {
+		this.spring.register(ReturnBeforeOffsetPostAuthorizeConfig.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		assertThatExceptionOfType(AccessDeniedException.class)
+			.isThrownBy(() -> this.methodSecurityService.allAnnotations(new ArrayList<>(list)));
+	}
+
+	@Test
+	@WithMockUser(roles = { "SECURED", "JSR250" })
+	public void allAnnotationsWhenAdviceBeforeOffsetPostAuthorizeThenReturnsFilteredList() {
+		this.spring.register(ReturnBeforeOffsetPostAuthorizeConfig.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		List<String> filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list));
+		assertThat(filtered).hasSize(3);
+		assertThat(filtered).containsExactly("DropOnPostAuthorize", "DropOnPostFilter", "DoNotDrop");
+	}
+
+	@Test
+	@WithMockUser(roles = { "SECURED", "JSR250" })
+	public void allAnnotationsWhenAdviceBeforeOffsetPostFilterThenReturnsFilteredList() {
+		this.spring.register(ReturnBeforeOffsetPostFilterConfig.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		List<String> filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list));
+		assertThat(filtered).hasSize(2);
+		assertThat(filtered).containsExactly("DropOnPostFilter", "DoNotDrop");
+	}
+
+	@Test
+	@WithMockUser(roles = { "SECURED", "JSR250" })
+	public void allAnnotationsWhenAdviceAfterAllOffsetThenReturnsFilteredList() {
+		this.spring.register(ReturnAfterAllOffsetConfig.class).autowire();
+		List<String> list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize",
+				"DropOnPostFilter", "DoNotDrop");
+		List<String> filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list));
+		assertThat(filtered).hasSize(1);
+		assertThat(filtered).containsExactly("DoNotDrop");
+	}
+
 	private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
 		return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
 	}
 
+	private static Advisor returnAdvisor(int order) {
+		JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
+		pointcut.setPattern(".*MethodSecurityServiceImpl.*");
+		MethodInterceptor interceptor = (mi) -> mi.getArguments()[0];
+		DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, interceptor);
+		advisor.setOrder(order);
+		return advisor;
+	}
+
 	@Configuration
 	@EnableCustomMethodSecurity
 	static class CustomMethodSecurityServiceConfig {
@@ -660,4 +766,105 @@ public class PrePostMethodSecurityConfigurationTests {
 
 	}
 
+	@Import(OffsetConfig.class)
+	static class ReturnBeforeOffsetPreFilterConfig {
+
+		@Bean
+		@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+		Advisor returnBeforePreFilter() {
+			return returnAdvisor(AuthorizationInterceptorsOrder.PRE_FILTER.getOrder() + OffsetConfig.OFFSET - 1);
+		}
+
+	}
+
+	@Configuration
+	@Import(OffsetConfig.class)
+	static class ReturnBeforeOffsetPreAuthorizeConfig {
+
+		@Bean
+		@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+		Advisor returnBeforePreAuthorize() {
+			return returnAdvisor(AuthorizationInterceptorsOrder.PRE_AUTHORIZE.getOrder() + OffsetConfig.OFFSET - 1);
+		}
+
+	}
+
+	@Configuration
+	@Import(OffsetConfig.class)
+	static class ReturnBeforeOffsetSecuredConfig {
+
+		@Bean
+		@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+		Advisor returnBeforeSecured() {
+			return returnAdvisor(AuthorizationInterceptorsOrder.SECURED.getOrder() + OffsetConfig.OFFSET - 1);
+		}
+
+	}
+
+	@Configuration
+	@Import(OffsetConfig.class)
+	static class ReturnBeforeOffsetJsr250Config {
+
+		@Bean
+		@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+		Advisor returnBeforeJsr250() {
+			return returnAdvisor(AuthorizationInterceptorsOrder.JSR250.getOrder() + OffsetConfig.OFFSET - 1);
+		}
+
+	}
+
+	@Configuration
+	@Import(OffsetConfig.class)
+	static class ReturnBeforeOffsetPostAuthorizeConfig {
+
+		@Bean
+		@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+		Advisor returnBeforePreAuthorize() {
+			return returnAdvisor(AuthorizationInterceptorsOrder.POST_AUTHORIZE.getOrder() + OffsetConfig.OFFSET - 1);
+		}
+
+	}
+
+	@Configuration
+	@Import(OffsetConfig.class)
+	static class ReturnBeforeOffsetPostFilterConfig {
+
+		@Bean
+		@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+		Advisor returnBeforePostFilter() {
+			return returnAdvisor(AuthorizationInterceptorsOrder.POST_FILTER.getOrder() + OffsetConfig.OFFSET - 1);
+		}
+
+	}
+
+	@Configuration
+	@Import(OffsetConfig.class)
+	static class ReturnAfterAllOffsetConfig {
+
+		@Bean
+		@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+		Advisor returnAfterAll() {
+			return returnAdvisor(AuthorizationInterceptorsOrder.POST_FILTER.getOrder() + OffsetConfig.OFFSET + 1);
+		}
+
+	}
+
+	@Configuration
+	@EnableMethodSecurity(offset = OffsetConfig.OFFSET, jsr250Enabled = true, securedEnabled = true)
+	static class OffsetConfig {
+
+		static final int OFFSET = 2;
+
+		@Bean
+		MethodSecurityService methodSecurityService() {
+			return new MethodSecurityServiceImpl();
+		}
+
+		@Bean
+		Authz authz() {
+			return new Authz();
+		}
+
+	}
+
 }