Skip to content

Commit 60652af

Browse files
committed
Polish InterceptMethodsBeanDefinitionDecorator
Issue gh-11328
1 parent bc6f494 commit 60652af

File tree

1 file changed

+130
-117
lines changed

1 file changed

+130
-117
lines changed

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

Lines changed: 130 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -69,27 +69,26 @@
6969
*/
7070
public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDecorator {
7171

72+
private final InternalAuthorizationManagerInterceptMethodsBeanDefinitionDecorator authorizationManagerDelegate = new InternalAuthorizationManagerInterceptMethodsBeanDefinitionDecorator();
73+
7274
private final BeanDefinitionDecorator delegate = new InternalInterceptMethodsBeanDefinitionDecorator();
7375

7476
@Override
7577
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
78+
if (this.authorizationManagerDelegate.supports(node)) {
79+
return this.authorizationManagerDelegate.decorate(node, definition, parserContext);
80+
}
7681
MethodConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
7782
return this.delegate.decorate(node, definition, parserContext);
7883
}
7984

80-
/**
81-
* This is the real class which does the work. We need access to the ParserContext in
82-
* order to do bean registration.
83-
*/
84-
static class InternalInterceptMethodsBeanDefinitionDecorator
85+
static class InternalAuthorizationManagerInterceptMethodsBeanDefinitionDecorator
8586
extends AbstractInterceptorDrivenBeanDefinitionDecorator {
8687

8788
static final String ATT_METHOD = "method";
8889

8990
static final String ATT_ACCESS = "access";
9091

91-
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
92-
9392
private static final String ATT_USE_AUTHORIZATION_MGR = "use-authorization-manager";
9493

9594
private static final String ATT_AUTHORIZATION_MGR = "authorization-manager-ref";
@@ -99,16 +98,6 @@ static class InternalInterceptMethodsBeanDefinitionDecorator
9998
@Override
10099
protected BeanDefinition createInterceptorDefinition(Node node) {
101100
Element interceptMethodsElt = (Element) node;
102-
if (Boolean.parseBoolean(interceptMethodsElt.getAttribute(ATT_USE_AUTHORIZATION_MGR))) {
103-
return createAuthorizationManagerInterceptorDefinition(interceptMethodsElt);
104-
}
105-
if (StringUtils.hasText(interceptMethodsElt.getAttribute(ATT_AUTHORIZATION_MGR))) {
106-
return createAuthorizationManagerInterceptorDefinition(interceptMethodsElt);
107-
}
108-
return createMethodSecurityInterceptorDefinition(interceptMethodsElt);
109-
}
110-
111-
private BeanDefinition createAuthorizationManagerInterceptorDefinition(Element interceptMethodsElt) {
112101
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder
113102
.rootBeanDefinition(AuthorizationManagerBeforeMethodInterceptor.class);
114103
interceptor.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
@@ -122,6 +111,14 @@ private BeanDefinition createAuthorizationManagerInterceptorDefinition(Element i
122111
.addConstructorArgValue(authorizationManager(managers)).getBeanDefinition();
123112
}
124113

114+
boolean supports(Node node) {
115+
Element interceptMethodsElt = (Element) node;
116+
if (Boolean.parseBoolean(interceptMethodsElt.getAttribute(ATT_USE_AUTHORIZATION_MGR))) {
117+
return true;
118+
}
119+
return StringUtils.hasText(interceptMethodsElt.getAttribute(ATT_AUTHORIZATION_MGR));
120+
}
121+
125122
private Pointcut pointcut(Element interceptorElt, Element protectElt) {
126123
String method = protectElt.getAttribute(ATT_METHOD);
127124
Class<?> javaType = javaType(interceptorElt, method);
@@ -159,139 +156,155 @@ private Class<?> javaType(Element interceptMethodsElt, String method) {
159156
return ClassUtils.resolveClassName(typeName, this.beanClassLoader);
160157
}
161158

162-
private BeanDefinition createMethodSecurityInterceptorDefinition(Element interceptMethodsElt) {
163-
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder
164-
.rootBeanDefinition(MethodSecurityInterceptor.class);
165-
// Default to autowiring to pick up after invocation mgr
166-
interceptor.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
167-
String accessManagerId = interceptMethodsElt.getAttribute(ATT_ACCESS_MGR);
168-
if (!StringUtils.hasText(accessManagerId)) {
169-
accessManagerId = BeanIds.METHOD_ACCESS_MANAGER;
159+
private static class PrefixBasedMethodMatcher implements MethodMatcher, Pointcut {
160+
161+
private final ClassFilter classFilter;
162+
163+
private final String methodPrefix;
164+
165+
PrefixBasedMethodMatcher(Class<?> javaType, String methodPrefix) {
166+
this.classFilter = new RootClassFilter(javaType);
167+
this.methodPrefix = methodPrefix;
170168
}
171-
interceptor.addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
172-
interceptor.addPropertyValue("authenticationManager",
173-
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
174-
// Lookup parent bean information
175-
String parentBeanClass = ((Element) interceptMethodsElt.getParentNode()).getAttribute("class");
176-
// Parse the included methods
177-
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
178-
Map<String, BeanDefinition> mappings = new ManagedMap<>();
179-
for (Element protectmethodElt : methods) {
180-
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
181-
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
182-
attributeBuilder.addConstructorArgValue(protectmethodElt.getAttribute(ATT_ACCESS));
183-
// Support inference of class names
184-
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
185-
if (methodName.lastIndexOf(".") == -1) {
186-
if (parentBeanClass != null && !"".equals(parentBeanClass)) {
187-
methodName = parentBeanClass + "." + methodName;
188-
}
189-
}
190-
mappings.put(methodName, attributeBuilder.getBeanDefinition());
169+
170+
@Override
171+
public ClassFilter getClassFilter() {
172+
return this.classFilter;
191173
}
192-
BeanDefinition metadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
193-
metadataSource.getConstructorArgumentValues().addGenericArgumentValue(mappings);
194-
interceptor.addPropertyValue("securityMetadataSource", metadataSource);
195-
return interceptor.getBeanDefinition();
196-
}
197174

198-
}
175+
@Override
176+
public MethodMatcher getMethodMatcher() {
177+
return this;
178+
}
199179

200-
private static class PrefixBasedMethodMatcher implements MethodMatcher, Pointcut {
180+
@Override
181+
public boolean matches(Method method, Class<?> targetClass) {
182+
return matches(this.methodPrefix, method.getName());
183+
}
201184

202-
private final ClassFilter classFilter;
185+
@Override
186+
public boolean isRuntime() {
187+
return false;
188+
}
203189

204-
private final Class<?> javaType;
190+
@Override
191+
public boolean matches(Method method, Class<?> targetClass, Object... args) {
192+
return matches(this.methodPrefix, method.getName());
193+
}
205194

206-
private final String methodPrefix;
195+
private boolean matches(String mappedName, String methodName) {
196+
boolean equals = methodName.equals(mappedName);
197+
return equals || prefixMatches(mappedName, methodName) || suffixMatches(mappedName, methodName);
198+
}
207199

208-
PrefixBasedMethodMatcher(Class<?> javaType, String methodPrefix) {
209-
this.classFilter = new RootClassFilter(javaType);
210-
this.javaType = javaType;
211-
this.methodPrefix = methodPrefix;
212-
}
200+
private boolean prefixMatches(String mappedName, String methodName) {
201+
return mappedName.endsWith("*")
202+
&& methodName.startsWith(mappedName.substring(0, mappedName.length() - 1));
203+
}
213204

214-
@Override
215-
public ClassFilter getClassFilter() {
216-
return this.classFilter;
217-
}
205+
private boolean suffixMatches(String mappedName, String methodName) {
206+
return mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1));
207+
}
218208

219-
@Override
220-
public MethodMatcher getMethodMatcher() {
221-
return this;
222209
}
223210

224-
@Override
225-
public boolean matches(Method method, Class<?> targetClass) {
226-
return matches(this.methodPrefix, method.getName());
227-
}
211+
private static class PointcutMatchingAuthorizationManager implements AuthorizationManager<MethodInvocation> {
228212

229-
@Override
230-
public boolean isRuntime() {
231-
return false;
232-
}
213+
private final Map<Pointcut, AuthorizationManager<MethodInvocation>> managers;
233214

234-
@Override
235-
public boolean matches(Method method, Class<?> targetClass, Object... args) {
236-
return matches(this.methodPrefix, method.getName());
237-
}
215+
PointcutMatchingAuthorizationManager(Map<Pointcut, AuthorizationManager<MethodInvocation>> managers) {
216+
this.managers = managers;
217+
}
238218

239-
private boolean matches(String mappedName, String methodName) {
240-
boolean equals = methodName.equals(mappedName);
241-
return equals || prefixMatches(mappedName, methodName) || suffixMatches(mappedName, methodName);
242-
}
219+
@Override
220+
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
221+
for (Map.Entry<Pointcut, AuthorizationManager<MethodInvocation>> entry : this.managers.entrySet()) {
222+
Class<?> targetClass = (object.getThis() != null) ? AopUtils.getTargetClass(object.getThis())
223+
: null;
224+
if (entry.getKey().getClassFilter().matches(targetClass)
225+
&& entry.getKey().getMethodMatcher().matches(object.getMethod(), targetClass)) {
226+
return entry.getValue().check(authentication, object);
227+
}
228+
}
229+
return new AuthorizationDecision(false);
230+
}
243231

244-
private boolean prefixMatches(String mappedName, String methodName) {
245-
return mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1));
246232
}
247233

248-
private boolean suffixMatches(String mappedName, String methodName) {
249-
return mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1));
250-
}
234+
private static class MethodExpressionAuthorizationManager implements AuthorizationManager<MethodInvocation> {
251235

252-
}
236+
private final Expression expression;
253237

254-
private static class PointcutMatchingAuthorizationManager implements AuthorizationManager<MethodInvocation> {
238+
private SecurityExpressionHandler<MethodInvocation> expressionHandler = new DefaultMethodSecurityExpressionHandler();
255239

256-
private final Map<Pointcut, AuthorizationManager<MethodInvocation>> managers;
240+
MethodExpressionAuthorizationManager(Expression expression) {
241+
this.expression = expression;
242+
}
257243

258-
PointcutMatchingAuthorizationManager(Map<Pointcut, AuthorizationManager<MethodInvocation>> managers) {
259-
this.managers = managers;
260-
}
244+
@Override
245+
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
246+
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, invocation);
247+
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, ctx);
248+
return new ExpressionAuthorizationDecision(granted, this.expression);
249+
}
261250

262-
@Override
263-
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
264-
for (Map.Entry<Pointcut, AuthorizationManager<MethodInvocation>> entry : this.managers.entrySet()) {
265-
Class<?> targetClass = (object.getThis() != null) ? AopUtils.getTargetClass(object.getThis()) : null;
266-
if (entry.getKey().getClassFilter().matches(targetClass)
267-
&& entry.getKey().getMethodMatcher().matches(object.getMethod(), targetClass)) {
268-
return entry.getValue().check(authentication, object);
269-
}
251+
void setExpressionHandler(SecurityExpressionHandler<MethodInvocation> expressionHandler) {
252+
this.expressionHandler = expressionHandler;
270253
}
271-
return new AuthorizationDecision(false);
254+
272255
}
273256

274257
}
275258

276-
private static class MethodExpressionAuthorizationManager implements AuthorizationManager<MethodInvocation> {
259+
/**
260+
* This is the real class which does the work. We need access to the ParserContext in
261+
* order to do bean registration.
262+
*/
263+
static class InternalInterceptMethodsBeanDefinitionDecorator
264+
extends AbstractInterceptorDrivenBeanDefinitionDecorator {
277265

278-
private final Expression expression;
266+
static final String ATT_METHOD = "method";
279267

280-
private SecurityExpressionHandler<MethodInvocation> expressionHandler = new DefaultMethodSecurityExpressionHandler();
268+
static final String ATT_ACCESS = "access";
281269

282-
MethodExpressionAuthorizationManager(Expression expression) {
283-
this.expression = expression;
284-
}
270+
private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
285271

286272
@Override
287-
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
288-
EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, invocation);
289-
boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, ctx);
290-
return new ExpressionAuthorizationDecision(granted, this.expression);
291-
}
292-
293-
void setExpressionHandler(SecurityExpressionHandler<MethodInvocation> expressionHandler) {
294-
this.expressionHandler = expressionHandler;
273+
protected BeanDefinition createInterceptorDefinition(Node node) {
274+
Element interceptMethodsElt = (Element) node;
275+
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder
276+
.rootBeanDefinition(MethodSecurityInterceptor.class);
277+
// Default to autowiring to pick up after invocation mgr
278+
interceptor.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
279+
String accessManagerId = interceptMethodsElt.getAttribute(ATT_ACCESS_MGR);
280+
if (!StringUtils.hasText(accessManagerId)) {
281+
accessManagerId = BeanIds.METHOD_ACCESS_MANAGER;
282+
}
283+
interceptor.addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
284+
interceptor.addPropertyValue("authenticationManager",
285+
new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
286+
// Lookup parent bean information
287+
String parentBeanClass = ((Element) interceptMethodsElt.getParentNode()).getAttribute("class");
288+
// Parse the included methods
289+
List<Element> methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, Elements.PROTECT);
290+
Map<String, BeanDefinition> mappings = new ManagedMap<>();
291+
for (Element protectmethodElt : methods) {
292+
BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
293+
attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
294+
attributeBuilder.addConstructorArgValue(protectmethodElt.getAttribute(ATT_ACCESS));
295+
// Support inference of class names
296+
String methodName = protectmethodElt.getAttribute(ATT_METHOD);
297+
if (methodName.lastIndexOf(".") == -1) {
298+
if (parentBeanClass != null && !"".equals(parentBeanClass)) {
299+
methodName = parentBeanClass + "." + methodName;
300+
}
301+
}
302+
mappings.put(methodName, attributeBuilder.getBeanDefinition());
303+
}
304+
BeanDefinition metadataSource = new RootBeanDefinition(MapBasedMethodSecurityMetadataSource.class);
305+
metadataSource.getConstructorArgumentValues().addGenericArgumentValue(mappings);
306+
interceptor.addPropertyValue("securityMetadataSource", metadataSource);
307+
return interceptor.getBeanDefinition();
295308
}
296309

297310
}

0 commit comments

Comments
 (0)