Skip to content

Commit a33e5db

Browse files
dbuosDaniel Bustamante Ospina
authored andcommitted
Make MethodSecurityEvaluationContext Delegates to MethodBasedEvaluationContext
Spring Security's MethodSecurityEvaluationContext should delegate to Spring Framework's MethodBasedEvaluationContext Fixes: gh-6224
1 parent 12ab2cc commit a33e5db

File tree

2 files changed

+18
-81
lines changed

2 files changed

+18
-81
lines changed
Lines changed: 10 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -15,105 +15,38 @@
1515
*/
1616
package org.springframework.security.access.expression.method;
1717

18-
import java.lang.reflect.Method;
19-
2018
import org.aopalliance.intercept.MethodInvocation;
2119
import org.apache.commons.logging.Log;
2220
import org.apache.commons.logging.LogFactory;
2321
import org.springframework.aop.framework.AopProxyUtils;
2422
import org.springframework.aop.support.AopUtils;
23+
import org.springframework.context.expression.MethodBasedEvaluationContext;
2524
import org.springframework.core.ParameterNameDiscoverer;
26-
import org.springframework.expression.spel.support.StandardEvaluationContext;
2725
import org.springframework.security.core.Authentication;
28-
import org.springframework.security.core.parameters.DefaultSecurityParameterNameDiscoverer;
26+
27+
import java.lang.reflect.Method;
2928

3029
/**
3130
* Internal security-specific EvaluationContext implementation which lazily adds the
3231
* method parameter values as variables (with the corresponding parameter names) if and
3332
* when they are required.
3433
*
3534
* @author Luke Taylor
35+
* @author Daniel Bustamante
3636
* @since 3.0
3737
*/
38-
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
38+
class MethodSecurityEvaluationContext extends MethodBasedEvaluationContext {
3939
private static final Log logger = LogFactory
4040
.getLog(MethodSecurityEvaluationContext.class);
4141

42-
private ParameterNameDiscoverer parameterNameDiscoverer;
43-
private final MethodInvocation mi;
44-
private boolean argumentsAdded;
45-
46-
/**
47-
* Intended for testing. Don't use in practice as it creates a new parameter resolver
48-
* for each instance. Use the constructor which takes the resolver, as an argument
49-
* thus allowing for caching.
50-
*/
51-
public MethodSecurityEvaluationContext(Authentication user, MethodInvocation mi) {
52-
this(user, mi, new DefaultSecurityParameterNameDiscoverer());
53-
}
5442

55-
public MethodSecurityEvaluationContext(Authentication user, MethodInvocation mi,
43+
MethodSecurityEvaluationContext(Authentication user, MethodInvocation mi,
5644
ParameterNameDiscoverer parameterNameDiscoverer) {
57-
this.mi = mi;
58-
this.parameterNameDiscoverer = parameterNameDiscoverer;
45+
super(mi.getThis(), getSpecificMethod(mi), mi.getArguments(), parameterNameDiscoverer);
5946
}
6047

61-
@Override
62-
public Object lookupVariable(String name) {
63-
Object variable = super.lookupVariable(name);
64-
65-
if (variable != null) {
66-
return variable;
67-
}
68-
69-
if (!argumentsAdded) {
70-
addArgumentsAsVariables();
71-
argumentsAdded = true;
72-
}
73-
74-
variable = super.lookupVariable(name);
75-
76-
if (variable != null) {
77-
return variable;
78-
}
79-
80-
return null;
81-
}
82-
83-
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
84-
this.parameterNameDiscoverer = parameterNameDiscoverer;
85-
}
86-
87-
private void addArgumentsAsVariables() {
88-
Object[] args = mi.getArguments();
89-
90-
if (args.length == 0) {
91-
return;
92-
}
93-
94-
Object targetObject = mi.getThis();
95-
// SEC-1454
96-
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(targetObject);
97-
98-
if (targetClass == null) {
99-
// TODO: Spring should do this, but there's a bug in ultimateTargetClass()
100-
// which returns null
101-
targetClass = targetObject.getClass();
102-
}
103-
104-
Method method = AopUtils.getMostSpecificMethod(mi.getMethod(), targetClass);
105-
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
106-
107-
if (paramNames == null) {
108-
logger.warn("Unable to resolve method parameter names for method: "
109-
+ method
110-
+ ". Debug symbol information is required if you are using parameter names in expressions.");
111-
return;
112-
}
113-
114-
for (int i = 0; i < args.length; i++) {
115-
super.setVariable(paramNames[i], args[i]);
116-
}
48+
private static Method getSpecificMethod(MethodInvocation mi) {
49+
return AopUtils.getMostSpecificMethod(mi.getMethod(), AopProxyUtils.ultimateTargetClass(mi.getThis()));
11750
}
11851

11952
}

core/src/test/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandlerTests.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@
3535

3636
import static org.assertj.core.api.Assertions.assertThat;
3737
import static org.mockito.ArgumentMatchers.any;
38-
import static org.mockito.Mockito.doReturn;
39-
import static org.mockito.Mockito.mock;
40-
import static org.mockito.Mockito.verify;
38+
import static org.mockito.Mockito.*;
4139

4240
@RunWith(MockitoJUnitRunner.class)
4341
public class DefaultMethodSecurityExpressionHandlerTests {
@@ -53,6 +51,8 @@ public class DefaultMethodSecurityExpressionHandlerTests {
5351
@Before
5452
public void setup() {
5553
handler = new DefaultMethodSecurityExpressionHandler();
54+
when(methodInvocation.getThis()).thenReturn(new Foo());
55+
when(methodInvocation.getMethod()).thenReturn(Foo.class.getMethods()[0]);
5656
}
5757

5858
@After
@@ -82,7 +82,6 @@ public void createEvaluationContextCustomTrustResolver() {
8282
@SuppressWarnings("unchecked")
8383
public void filterWhenUsingStreamThenFiltersStream() {
8484
final Stream<String> stream = Stream.of("1", "2", "3");
85-
8685
Expression expression = handler.getExpressionParser().parseExpression("filterObject ne '2'");
8786

8887
EvaluationContext context = handler.createEvaluationContext(authentication,
@@ -108,4 +107,9 @@ public void filterStreamWhenClosedThenUpstreamGetsClosed() {
108107
((Stream) handler.filter(upstream, expression, context)).close();
109108
verify(upstream).close();
110109
}
110+
111+
private static class Foo {
112+
public void bar(){
113+
}
114+
}
111115
}

0 commit comments

Comments
 (0)