Skip to content

Commit 9cd7c7b

Browse files
committed
Add SecurityContextHolderStrategy XML Configuration for Method Security
Issue gh-11061
1 parent da57bac commit 9cd7c7b

File tree

8 files changed

+256
-55
lines changed

8 files changed

+256
-55
lines changed

config/src/main/java/org/springframework/security/config/method/MethodSecurityBeanDefinitionParser.java

+77-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -21,9 +21,11 @@
2121
import org.w3c.dom.Element;
2222

2323
import org.springframework.aop.config.AopNamespaceUtils;
24+
import org.springframework.beans.BeanMetadataElement;
2425
import org.springframework.beans.BeansException;
2526
import org.springframework.beans.factory.FactoryBean;
2627
import org.springframework.beans.factory.config.BeanDefinition;
28+
import org.springframework.beans.factory.config.RuntimeBeanReference;
2729
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
2830
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2931
import org.springframework.beans.factory.xml.BeanDefinitionParser;
@@ -41,6 +43,9 @@
4143
import org.springframework.security.authorization.method.PreFilterAuthorizationMethodInterceptor;
4244
import org.springframework.security.config.Elements;
4345
import org.springframework.security.config.core.GrantedAuthorityDefaults;
46+
import org.springframework.security.core.context.SecurityContextHolder;
47+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
48+
import org.springframework.util.StringUtils;
4449
import org.springframework.util.xml.DomUtils;
4550

4651
/**
@@ -61,26 +66,33 @@ public class MethodSecurityBeanDefinitionParser implements BeanDefinitionParser
6166

6267
private static final String ATT_REF = "ref";
6368

69+
private static final String ATT_SECURITY_CONTEXT_HOLDER_STRATEGY_REF = "security-context-holder-strategy-ref";
70+
6471
@Override
6572
public BeanDefinition parse(Element element, ParserContext pc) {
6673
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
6774
pc.extractSource(element));
6875
pc.pushContainingComponent(compositeDef);
76+
BeanMetadataElement securityContextHolderStrategy = getSecurityContextHolderStrategy(element);
6977
boolean prePostAnnotationsEnabled = !element.hasAttribute(ATT_USE_PREPOST)
7078
|| "true".equals(element.getAttribute(ATT_USE_PREPOST));
7179
if (prePostAnnotationsEnabled) {
7280
BeanDefinitionBuilder preFilterInterceptor = BeanDefinitionBuilder
7381
.rootBeanDefinition(PreFilterAuthorizationMethodInterceptor.class)
74-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
82+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
83+
.addPropertyValue("securityContextHolderStrategy", securityContextHolderStrategy);
7584
BeanDefinitionBuilder preAuthorizeInterceptor = BeanDefinitionBuilder
7685
.rootBeanDefinition(PreAuthorizeAuthorizationMethodInterceptor.class)
77-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
86+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
87+
.addPropertyValue("securityContextHolderStrategy", securityContextHolderStrategy);
7888
BeanDefinitionBuilder postAuthorizeInterceptor = BeanDefinitionBuilder
7989
.rootBeanDefinition(PostAuthorizeAuthorizationMethodInterceptor.class)
80-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
90+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
91+
.addPropertyValue("securityContextHolderStrategy", securityContextHolderStrategy);
8192
BeanDefinitionBuilder postFilterInterceptor = BeanDefinitionBuilder
8293
.rootBeanDefinition(PostFilterAuthorizationMethodInterceptor.class)
83-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
94+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
95+
.addPropertyValue("securityContextHolderStrategy", securityContextHolderStrategy);
8496
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
8597
if (expressionHandlerElt != null) {
8698
String expressionHandlerRef = expressionHandlerElt.getAttribute(ATT_REF);
@@ -110,15 +122,18 @@ public BeanDefinition parse(Element element, ParserContext pc) {
110122
if (securedEnabled) {
111123
BeanDefinitionBuilder securedInterceptor = BeanDefinitionBuilder
112124
.rootBeanDefinition(AuthorizationManagerBeforeMethodInterceptor.class)
113-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).setFactoryMethod("secured");
125+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
126+
.addPropertyValue("securityContextHolderStrategy", securityContextHolderStrategy)
127+
.setFactoryMethod("secured");
114128
pc.getRegistry().registerBeanDefinition("securedAuthorizationMethodInterceptor",
115129
securedInterceptor.getBeanDefinition());
116130
}
117131
boolean jsr250Enabled = "true".equals(element.getAttribute(ATT_USE_JSR250));
118132
if (jsr250Enabled) {
119133
BeanDefinitionBuilder jsr250Interceptor = BeanDefinitionBuilder
120134
.rootBeanDefinition(Jsr250AuthorizationMethodInterceptor.class)
121-
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
135+
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
136+
.addPropertyValue("securityContextHolderStrategy", securityContextHolderStrategy);
122137
pc.getRegistry().registerBeanDefinition("jsr250AuthorizationMethodInterceptor",
123138
jsr250Interceptor.getBeanDefinition());
124139
}
@@ -127,6 +142,14 @@ public BeanDefinition parse(Element element, ParserContext pc) {
127142
return null;
128143
}
129144

145+
private BeanMetadataElement getSecurityContextHolderStrategy(Element methodSecurityElmt) {
146+
String holderStrategyRef = methodSecurityElmt.getAttribute(ATT_SECURITY_CONTEXT_HOLDER_STRATEGY_REF);
147+
if (StringUtils.hasText(holderStrategyRef)) {
148+
return new RuntimeBeanReference(holderStrategyRef);
149+
}
150+
return BeanDefinitionBuilder.rootBeanDefinition(SecurityContextHolderStrategyFactory.class).getBeanDefinition();
151+
}
152+
130153
public static final class MethodSecurityExpressionHandlerBean
131154
implements FactoryBean<MethodSecurityExpressionHandler>, ApplicationContextAware {
132155

@@ -158,11 +181,17 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
158181
public static final class Jsr250AuthorizationMethodInterceptor
159182
implements FactoryBean<AuthorizationManagerBeforeMethodInterceptor>, ApplicationContextAware {
160183

184+
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
185+
.getContextHolderStrategy();
186+
161187
private final Jsr250AuthorizationManager manager = new Jsr250AuthorizationManager();
162188

163189
@Override
164190
public AuthorizationManagerBeforeMethodInterceptor getObject() {
165-
return AuthorizationManagerBeforeMethodInterceptor.jsr250(this.manager);
191+
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
192+
.jsr250(this.manager);
193+
interceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
194+
return interceptor;
166195
}
167196

168197
@Override
@@ -181,23 +210,37 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
181210
}
182211
}
183212

213+
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
214+
this.securityContextHolderStrategy = securityContextHolderStrategy;
215+
}
216+
184217
}
185218

186219
public static final class PreAuthorizeAuthorizationMethodInterceptor
187220
implements FactoryBean<AuthorizationManagerBeforeMethodInterceptor> {
188221

222+
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
223+
.getContextHolderStrategy();
224+
189225
private final PreAuthorizeAuthorizationManager manager = new PreAuthorizeAuthorizationManager();
190226

191227
@Override
192228
public AuthorizationManagerBeforeMethodInterceptor getObject() {
193-
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize(this.manager);
229+
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
230+
.preAuthorize(this.manager);
231+
interceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
232+
return interceptor;
194233
}
195234

196235
@Override
197236
public Class<?> getObjectType() {
198237
return AuthorizationManagerBeforeMethodInterceptor.class;
199238
}
200239

240+
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
241+
this.securityContextHolderStrategy = securityContextHolderStrategy;
242+
}
243+
201244
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
202245
this.manager.setExpressionHandler(expressionHandler);
203246
}
@@ -207,22 +250,46 @@ public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandl
207250
public static final class PostAuthorizeAuthorizationMethodInterceptor
208251
implements FactoryBean<AuthorizationManagerAfterMethodInterceptor> {
209252

253+
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
254+
.getContextHolderStrategy();
255+
210256
private final PostAuthorizeAuthorizationManager manager = new PostAuthorizeAuthorizationManager();
211257

212258
@Override
213259
public AuthorizationManagerAfterMethodInterceptor getObject() {
214-
return AuthorizationManagerAfterMethodInterceptor.postAuthorize(this.manager);
260+
AuthorizationManagerAfterMethodInterceptor interceptor = AuthorizationManagerAfterMethodInterceptor
261+
.postAuthorize(this.manager);
262+
interceptor.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
263+
return interceptor;
215264
}
216265

217266
@Override
218267
public Class<?> getObjectType() {
219268
return AuthorizationManagerAfterMethodInterceptor.class;
220269
}
221270

271+
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
272+
this.securityContextHolderStrategy = securityContextHolderStrategy;
273+
}
274+
222275
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
223276
this.manager.setExpressionHandler(expressionHandler);
224277
}
225278

226279
}
227280

281+
static class SecurityContextHolderStrategyFactory implements FactoryBean<SecurityContextHolderStrategy> {
282+
283+
@Override
284+
public SecurityContextHolderStrategy getObject() throws Exception {
285+
return SecurityContextHolder.getContextHolderStrategy();
286+
}
287+
288+
@Override
289+
public Class<?> getObjectType() {
290+
return SecurityContextHolderStrategy.class;
291+
}
292+
293+
}
294+
228295
}

config/src/main/resources/org/springframework/security/config/spring-security-5.8.rnc

+3
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ method-security.attlist &=
211211
method-security.attlist &=
212212
## If true, class-based proxying will be used instead of interface-based proxying.
213213
attribute proxy-target-class {xsd:boolean}?
214+
method-security.attlist &=
215+
## Specifies the security context holder strategy to use, by default uses a ThreadLocal-based strategy
216+
attribute security-context-holder-strategy-ref {xsd:string}?
214217

215218
global-method-security =
216219
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250.

0 commit comments

Comments
 (0)