Skip to content

Commit 99218db

Browse files
ykardziyakajzheaux
authored andcommitted
Add order offset to @EnableMethodSecurity
Closes gh-13214
1 parent c19f3d9 commit 99218db

File tree

7 files changed

+280
-10
lines changed

7 files changed

+280
-10
lines changed

config/src/main/java/org/springframework/security/config/annotation/method/configuration/EnableMethodSecurity.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -87,4 +87,14 @@
8787
*/
8888
AdviceMode mode() default AdviceMode.PROXY;
8989

90+
/**
91+
* Indicate additional offset in the ordering of the execution of the security
92+
* interceptors when multiple advices are applied at a specific joinpoint. I.e.,
93+
* precedence of each security interceptor enabled by this annotation will be
94+
* calculated as sum of its default precedence and offset. The default is 0.
95+
* @return the offset in the order the security advisor should be applied
96+
* @since 6.3
97+
*/
98+
int offset() default 0;
99+
90100
}

config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MethodSecurityConfiguration.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import org.springframework.beans.factory.config.BeanDefinition;
2525
import org.springframework.context.annotation.Bean;
2626
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.context.annotation.ImportAware;
2728
import org.springframework.context.annotation.Role;
29+
import org.springframework.core.type.AnnotationMetadata;
2830
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
2931
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
3032
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
@@ -45,14 +47,17 @@
4547
*/
4648
@Configuration(proxyBeanMethods = false)
4749
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
48-
final class Jsr250MethodSecurityConfiguration {
50+
final class Jsr250MethodSecurityConfiguration implements ImportAware {
51+
52+
private int interceptorOrderOffset;
4953

5054
@Bean
5155
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
5256
static MethodInterceptor jsr250AuthorizationMethodInterceptor(
5357
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
5458
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
55-
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider) {
59+
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
60+
Jsr250MethodSecurityConfiguration configuration) {
5661
Jsr250AuthorizationManager jsr250 = new Jsr250AuthorizationManager();
5762
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
5863
RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
@@ -65,8 +70,15 @@ static MethodInterceptor jsr250AuthorizationMethodInterceptor(
6570
registryProvider, jsr250);
6671
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
6772
.jsr250(manager);
73+
interceptor.setOrder(interceptor.getOrder() + configuration.interceptorOrderOffset);
6874
interceptor.setSecurityContextHolderStrategy(strategy);
6975
return interceptor;
7076
}
7177

78+
@Override
79+
public void setImportMetadata(AnnotationMetadata importMetadata) {
80+
EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
81+
this.interceptorOrderOffset = annotation.offset();
82+
}
83+
7284
}

config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import org.springframework.context.ApplicationContext;
2828
import org.springframework.context.annotation.Bean;
2929
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.context.annotation.ImportAware;
3031
import org.springframework.context.annotation.Role;
32+
import org.springframework.core.type.AnnotationMetadata;
3133
import org.springframework.expression.EvaluationContext;
3234
import org.springframework.expression.Expression;
3335
import org.springframework.expression.ExpressionParser;
@@ -58,16 +60,20 @@
5860
*/
5961
@Configuration(proxyBeanMethods = false)
6062
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
61-
final class PrePostMethodSecurityConfiguration {
63+
final class PrePostMethodSecurityConfiguration implements ImportAware {
64+
65+
private int interceptorOrderOffset;
6266

6367
@Bean
6468
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
6569
static MethodInterceptor preFilterAuthorizationMethodInterceptor(
6670
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
6771
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
6872
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
69-
ObjectProvider<RoleHierarchy> roleHierarchyProvider, ApplicationContext context) {
73+
ObjectProvider<RoleHierarchy> roleHierarchyProvider, PrePostMethodSecurityConfiguration configuration,
74+
ApplicationContext context) {
7075
PreFilterAuthorizationMethodInterceptor preFilter = new PreFilterAuthorizationMethodInterceptor();
76+
preFilter.setOrder(preFilter.getOrder() + configuration.interceptorOrderOffset);
7177
strategyProvider.ifAvailable(preFilter::setSecurityContextHolderStrategy);
7278
preFilter.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
7379
defaultsProvider, roleHierarchyProvider, context));
@@ -82,12 +88,13 @@ static MethodInterceptor preAuthorizeAuthorizationMethodInterceptor(
8288
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
8389
ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
8490
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
85-
ApplicationContext context) {
91+
PrePostMethodSecurityConfiguration configuration, ApplicationContext context) {
8692
PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
8793
manager.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
8894
defaultsProvider, roleHierarchyProvider, context));
8995
AuthorizationManagerBeforeMethodInterceptor preAuthorize = AuthorizationManagerBeforeMethodInterceptor
9096
.preAuthorize(manager(manager, registryProvider));
97+
preAuthorize.setOrder(preAuthorize.getOrder() + configuration.interceptorOrderOffset);
9198
strategyProvider.ifAvailable(preAuthorize::setSecurityContextHolderStrategy);
9299
eventPublisherProvider.ifAvailable(preAuthorize::setAuthorizationEventPublisher);
93100
return preAuthorize;
@@ -101,12 +108,13 @@ static MethodInterceptor postAuthorizeAuthorizationMethodInterceptor(
101108
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
102109
ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
103110
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
104-
ApplicationContext context) {
111+
PrePostMethodSecurityConfiguration configuration, ApplicationContext context) {
105112
PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
106113
manager.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
107114
defaultsProvider, roleHierarchyProvider, context));
108115
AuthorizationManagerAfterMethodInterceptor postAuthorize = AuthorizationManagerAfterMethodInterceptor
109116
.postAuthorize(manager(manager, registryProvider));
117+
postAuthorize.setOrder(postAuthorize.getOrder() + configuration.interceptorOrderOffset);
110118
strategyProvider.ifAvailable(postAuthorize::setSecurityContextHolderStrategy);
111119
eventPublisherProvider.ifAvailable(postAuthorize::setAuthorizationEventPublisher);
112120
return postAuthorize;
@@ -118,8 +126,10 @@ static MethodInterceptor postFilterAuthorizationMethodInterceptor(
118126
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
119127
ObjectProvider<MethodSecurityExpressionHandler> expressionHandlerProvider,
120128
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
121-
ObjectProvider<RoleHierarchy> roleHierarchyProvider, ApplicationContext context) {
129+
ObjectProvider<RoleHierarchy> roleHierarchyProvider, PrePostMethodSecurityConfiguration configuration,
130+
ApplicationContext context) {
122131
PostFilterAuthorizationMethodInterceptor postFilter = new PostFilterAuthorizationMethodInterceptor();
132+
postFilter.setOrder(postFilter.getOrder() + configuration.interceptorOrderOffset);
123133
strategyProvider.ifAvailable(postFilter::setSecurityContextHolderStrategy);
124134
postFilter.setExpressionHandler(new DeferringMethodSecurityExpressionHandler(expressionHandlerProvider,
125135
defaultsProvider, roleHierarchyProvider, context));
@@ -142,6 +152,12 @@ static <T> AuthorizationManager<T> manager(AuthorizationManager<T> delegate,
142152
return new DeferringObservationAuthorizationManager<>(registryProvider, delegate);
143153
}
144154

155+
@Override
156+
public void setImportMetadata(AnnotationMetadata importMetadata) {
157+
EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
158+
this.interceptorOrderOffset = annotation.offset();
159+
}
160+
145161
private static final class DeferringMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {
146162

147163
private final Supplier<MethodSecurityExpressionHandler> expressionHandler;

config/src/main/java/org/springframework/security/config/annotation/method/configuration/SecuredMethodSecurityConfiguration.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import org.springframework.beans.factory.config.BeanDefinition;
2525
import org.springframework.context.annotation.Bean;
2626
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.context.annotation.ImportAware;
2728
import org.springframework.context.annotation.Role;
29+
import org.springframework.core.type.AnnotationMetadata;
2830
import org.springframework.security.access.annotation.Secured;
2931
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
3032
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
@@ -45,13 +47,16 @@
4547
*/
4648
@Configuration(proxyBeanMethods = false)
4749
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
48-
final class SecuredMethodSecurityConfiguration {
50+
final class SecuredMethodSecurityConfiguration implements ImportAware {
51+
52+
private int interceptorOrderOffset;
4953

5054
@Bean
5155
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
5256
static MethodInterceptor securedAuthorizationMethodInterceptor(
5357
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
54-
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider) {
58+
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
59+
SecuredMethodSecurityConfiguration configuration) {
5560
SecuredAuthorizationManager secured = new SecuredAuthorizationManager();
5661
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
5762
RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
@@ -63,8 +68,15 @@ static MethodInterceptor securedAuthorizationMethodInterceptor(
6368
registryProvider, secured);
6469
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
6570
.secured(manager);
71+
interceptor.setOrder(interceptor.getOrder() + configuration.interceptorOrderOffset);
6672
interceptor.setSecurityContextHolderStrategy(strategy);
6773
return interceptor;
6874
}
6975

76+
@Override
77+
public void setImportMetadata(AnnotationMetadata importMetadata) {
78+
EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
79+
this.interceptorOrderOffset = annotation.offset();
80+
}
81+
7082
}

config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ public interface MethodSecurityService {
9696
@PostAuthorize("returnObject.size == 2")
9797
List<String> manyAnnotations(List<String> array);
9898

99+
@PreFilter("filterObject != 'DropOnPreFilter'")
100+
@PreAuthorize("#list.remove('DropOnPreAuthorize')")
101+
@Secured("ROLE_SECURED")
102+
@RolesAllowed("JSR250")
103+
@PostAuthorize("#list.remove('DropOnPostAuthorize')")
104+
@PostFilter("filterObject != 'DropOnPostFilter'")
105+
List<String> allAnnotations(List<String> list);
106+
99107
@RequireUserRole
100108
@RequireAdminRole
101109
void repeatedAnnotations();

config/src/test/java/org/springframework/security/config/annotation/method/configuration/MethodSecurityServiceImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ public List<String> manyAnnotations(List<String> object) {
117117
return object;
118118
}
119119

120+
@Override
121+
public List<String> allAnnotations(List<String> list) {
122+
return null;
123+
}
124+
120125
@Override
121126
public void repeatedAnnotations() {
122127
}

0 commit comments

Comments
 (0)