diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableMethodSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableMethodSecurity.java index b65f3369db..919de3e409 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableMethodSecurity.java +++ b/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; + } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MethodSecurityConfiguration.java index 938d53661a..c7bee6a725 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MethodSecurityConfiguration.java +++ b/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 defaultsProvider, ObjectProvider strategyProvider, - ObjectProvider registryProvider, ObjectProvider roleHierarchyProvider) { + ObjectProvider registryProvider, ObjectProvider 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(); + } + } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java index 51c497eba3..31091be05c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java +++ b/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 defaultsProvider, ObjectProvider expressionHandlerProvider, ObjectProvider strategyProvider, - ObjectProvider roleHierarchyProvider, ApplicationContext context) { + ObjectProvider 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 strategyProvider, ObjectProvider eventPublisherProvider, ObjectProvider registryProvider, ObjectProvider 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 strategyProvider, ObjectProvider eventPublisherProvider, ObjectProvider registryProvider, ObjectProvider 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 defaultsProvider, ObjectProvider expressionHandlerProvider, ObjectProvider strategyProvider, - ObjectProvider roleHierarchyProvider, ApplicationContext context) { + ObjectProvider 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 expressionHandler; diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/SecuredMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/SecuredMethodSecurityConfiguration.java index 4e10150dc1..78ea66606c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/SecuredMethodSecurityConfiguration.java +++ b/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 strategyProvider, - ObjectProvider registryProvider, ObjectProvider roleHierarchyProvider) { + ObjectProvider registryProvider, ObjectProvider 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(); + } + } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityService.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityService.java index f7db88a33c..00451610ed 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityService.java +++ b/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 manyAnnotations(List array); + @PreFilter("filterObject != 'DropOnPreFilter'") + @PreAuthorize("#list.remove('DropOnPreAuthorize')") + @Secured("ROLE_SECURED") + @RolesAllowed("JSR250") + @PostAuthorize("#list.remove('DropOnPostAuthorize')") + @PostFilter("filterObject != 'DropOnPostFilter'") + List allAnnotations(List list); + @RequireUserRole @RequireAdminRole void repeatedAnnotations(); diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityServiceImpl.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityServiceImpl.java index 133395e911..ebe851d1f3 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityServiceImpl.java +++ b/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 allAnnotations(List list) { + return null; + } + @Override public void repeatedAnnotations() { } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java index d9138d4a33..746fb13785 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java +++ b/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 list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize", + "DropOnPostFilter", "DoNotDrop"); + List 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 list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize", + "DropOnPostFilter", "DoNotDrop"); + List 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 list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize", + "DropOnPostFilter", "DoNotDrop"); + List 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 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 list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize", + "DropOnPostFilter", "DoNotDrop"); + List 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 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 list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize", + "DropOnPostFilter", "DoNotDrop"); + List 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 list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize", + "DropOnPostFilter", "DoNotDrop"); + List 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 list = Arrays.asList("DropOnPreFilter", "DropOnPreAuthorize", "DropOnPostAuthorize", + "DropOnPostFilter", "DoNotDrop"); + List filtered = this.methodSecurityService.allAnnotations(new ArrayList<>(list)); + assertThat(filtered).hasSize(1); + assertThat(filtered).containsExactly("DoNotDrop"); + } + private static Consumer 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(); + } + + } + }