|
@@ -69,27 +69,26 @@ import org.springframework.util.xml.DomUtils;
|
|
*/
|
|
*/
|
|
public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
|
public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDecorator {
|
|
|
|
|
|
|
|
+ private final InternalAuthorizationManagerInterceptMethodsBeanDefinitionDecorator authorizationManagerDelegate =
|
|
|
|
+ new InternalAuthorizationManagerInterceptMethodsBeanDefinitionDecorator();
|
|
private final BeanDefinitionDecorator delegate = new InternalInterceptMethodsBeanDefinitionDecorator();
|
|
private final BeanDefinitionDecorator delegate = new InternalInterceptMethodsBeanDefinitionDecorator();
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
|
|
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
|
|
|
|
+ if (this.authorizationManagerDelegate.supports(node)) {
|
|
|
|
+ return this.authorizationManagerDelegate.decorate(node, definition, parserContext);
|
|
|
|
+ }
|
|
MethodConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
|
|
MethodConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
|
|
return this.delegate.decorate(node, definition, parserContext);
|
|
return this.delegate.decorate(node, definition, parserContext);
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * This is the real class which does the work. We need access to the ParserContext in
|
|
|
|
- * order to do bean registration.
|
|
|
|
- */
|
|
|
|
- static class InternalInterceptMethodsBeanDefinitionDecorator
|
|
|
|
|
|
+ static class InternalAuthorizationManagerInterceptMethodsBeanDefinitionDecorator
|
|
extends AbstractInterceptorDrivenBeanDefinitionDecorator {
|
|
extends AbstractInterceptorDrivenBeanDefinitionDecorator {
|
|
|
|
|
|
static final String ATT_METHOD = "method";
|
|
static final String ATT_METHOD = "method";
|
|
|
|
|
|
static final String ATT_ACCESS = "access";
|
|
static final String ATT_ACCESS = "access";
|
|
|
|
|
|
- private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
|
|
|
-
|
|
|
|
private static final String ATT_USE_AUTHORIZATION_MGR = "use-authorization-manager";
|
|
private static final String ATT_USE_AUTHORIZATION_MGR = "use-authorization-manager";
|
|
|
|
|
|
private static final String ATT_AUTHORIZATION_MGR = "authorization-manager-ref";
|
|
private static final String ATT_AUTHORIZATION_MGR = "authorization-manager-ref";
|
|
@@ -99,16 +98,6 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
|
|
@Override
|
|
@Override
|
|
protected BeanDefinition createInterceptorDefinition(Node node) {
|
|
protected BeanDefinition createInterceptorDefinition(Node node) {
|
|
Element interceptMethodsElt = (Element) node;
|
|
Element interceptMethodsElt = (Element) node;
|
|
- if (Boolean.parseBoolean(interceptMethodsElt.getAttribute(ATT_USE_AUTHORIZATION_MGR))) {
|
|
|
|
- return createAuthorizationManagerInterceptorDefinition(interceptMethodsElt);
|
|
|
|
- }
|
|
|
|
- if (StringUtils.hasText(interceptMethodsElt.getAttribute(ATT_AUTHORIZATION_MGR))) {
|
|
|
|
- return createAuthorizationManagerInterceptorDefinition(interceptMethodsElt);
|
|
|
|
- }
|
|
|
|
- return createMethodSecurityInterceptorDefinition(interceptMethodsElt);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private BeanDefinition createAuthorizationManagerInterceptorDefinition(Element interceptMethodsElt) {
|
|
|
|
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder
|
|
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder
|
|
.rootBeanDefinition(AuthorizationManagerBeforeMethodInterceptor.class);
|
|
.rootBeanDefinition(AuthorizationManagerBeforeMethodInterceptor.class);
|
|
interceptor.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
|
interceptor.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
|
@@ -122,6 +111,14 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
|
|
.addConstructorArgValue(authorizationManager(managers)).getBeanDefinition();
|
|
.addConstructorArgValue(authorizationManager(managers)).getBeanDefinition();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ boolean supports(Node node) {
|
|
|
|
+ Element interceptMethodsElt = (Element) node;
|
|
|
|
+ if (Boolean.parseBoolean(interceptMethodsElt.getAttribute(ATT_USE_AUTHORIZATION_MGR))) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return StringUtils.hasText(interceptMethodsElt.getAttribute(ATT_AUTHORIZATION_MGR));
|
|
|
|
+ }
|
|
|
|
+
|
|
private Pointcut pointcut(Element interceptorElt, Element protectElt) {
|
|
private Pointcut pointcut(Element interceptorElt, Element protectElt) {
|
|
String method = protectElt.getAttribute(ATT_METHOD);
|
|
String method = protectElt.getAttribute(ATT_METHOD);
|
|
Class<?> javaType = javaType(interceptorElt, method);
|
|
Class<?> javaType = javaType(interceptorElt, method);
|
|
@@ -159,7 +156,118 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
|
|
return ClassUtils.resolveClassName(typeName, this.beanClassLoader);
|
|
return ClassUtils.resolveClassName(typeName, this.beanClassLoader);
|
|
}
|
|
}
|
|
|
|
|
|
- private BeanDefinition createMethodSecurityInterceptorDefinition(Element interceptMethodsElt) {
|
|
|
|
|
|
+ private static class PrefixBasedMethodMatcher implements MethodMatcher, Pointcut {
|
|
|
|
+
|
|
|
|
+ private final ClassFilter classFilter;
|
|
|
|
+
|
|
|
|
+ private final String methodPrefix;
|
|
|
|
+
|
|
|
|
+ PrefixBasedMethodMatcher(Class<?> javaType, String methodPrefix) {
|
|
|
|
+ this.classFilter = new RootClassFilter(javaType);
|
|
|
|
+ this.methodPrefix = methodPrefix;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public ClassFilter getClassFilter() {
|
|
|
|
+ return this.classFilter;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public MethodMatcher getMethodMatcher() {
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean matches(Method method, Class<?> targetClass) {
|
|
|
|
+ return matches(this.methodPrefix, method.getName());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean isRuntime() {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
|
|
|
+ return matches(this.methodPrefix, method.getName());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean matches(String mappedName, String methodName) {
|
|
|
|
+ boolean equals = methodName.equals(mappedName);
|
|
|
|
+ return equals || prefixMatches(mappedName, methodName) || suffixMatches(mappedName, methodName);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean prefixMatches(String mappedName, String methodName) {
|
|
|
|
+ return mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean suffixMatches(String mappedName, String methodName) {
|
|
|
|
+ return mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static class PointcutMatchingAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
|
|
|
+
|
|
|
|
+ private final Map<Pointcut, AuthorizationManager<MethodInvocation>> managers;
|
|
|
|
+
|
|
|
|
+ PointcutMatchingAuthorizationManager(Map<Pointcut, AuthorizationManager<MethodInvocation>> managers) {
|
|
|
|
+ this.managers = managers;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
|
|
|
|
+ for (Map.Entry<Pointcut, AuthorizationManager<MethodInvocation>> entry : this.managers.entrySet()) {
|
|
|
|
+ Class<?> targetClass = (object.getThis() != null) ? AopUtils.getTargetClass(object.getThis()) : null;
|
|
|
|
+ if (entry.getKey().getClassFilter().matches(targetClass)
|
|
|
|
+ && entry.getKey().getMethodMatcher().matches(object.getMethod(), targetClass)) {
|
|
|
|
+ return entry.getValue().check(authentication, object);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return new AuthorizationDecision(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static class MethodExpressionAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
|
|
|
+
|
|
|
|
+ private final Expression expression;
|
|
|
|
+
|
|
|
|
+ private SecurityExpressionHandler<MethodInvocation> expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
|
|
|
+
|
|
|
|
+ MethodExpressionAuthorizationManager(Expression expression) {
|
|
|
|
+ this.expression = expression;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
|
|
|
|
+ EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, invocation);
|
|
|
|
+ boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, ctx);
|
|
|
|
+ return new ExpressionAuthorizationDecision(granted, this.expression);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void setExpressionHandler(SecurityExpressionHandler<MethodInvocation> expressionHandler) {
|
|
|
|
+ this.expressionHandler = expressionHandler;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * This is the real class which does the work. We need access to the ParserContext in
|
|
|
|
+ * order to do bean registration.
|
|
|
|
+ */
|
|
|
|
+ static class InternalInterceptMethodsBeanDefinitionDecorator
|
|
|
|
+ extends AbstractInterceptorDrivenBeanDefinitionDecorator {
|
|
|
|
+
|
|
|
|
+ static final String ATT_METHOD = "method";
|
|
|
|
+
|
|
|
|
+ static final String ATT_ACCESS = "access";
|
|
|
|
+
|
|
|
|
+ private static final String ATT_ACCESS_MGR = "access-decision-manager-ref";
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ protected BeanDefinition createInterceptorDefinition(Node node) {
|
|
|
|
+ Element interceptMethodsElt = (Element) node;
|
|
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder
|
|
BeanDefinitionBuilder interceptor = BeanDefinitionBuilder
|
|
.rootBeanDefinition(MethodSecurityInterceptor.class);
|
|
.rootBeanDefinition(MethodSecurityInterceptor.class);
|
|
// Default to autowiring to pick up after invocation mgr
|
|
// Default to autowiring to pick up after invocation mgr
|
|
@@ -197,103 +305,4 @@ public class InterceptMethodsBeanDefinitionDecorator implements BeanDefinitionDe
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- private static class PrefixBasedMethodMatcher implements MethodMatcher, Pointcut {
|
|
|
|
-
|
|
|
|
- private final ClassFilter classFilter;
|
|
|
|
-
|
|
|
|
- private final Class<?> javaType;
|
|
|
|
-
|
|
|
|
- private final String methodPrefix;
|
|
|
|
-
|
|
|
|
- PrefixBasedMethodMatcher(Class<?> javaType, String methodPrefix) {
|
|
|
|
- this.classFilter = new RootClassFilter(javaType);
|
|
|
|
- this.javaType = javaType;
|
|
|
|
- this.methodPrefix = methodPrefix;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public ClassFilter getClassFilter() {
|
|
|
|
- return this.classFilter;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public MethodMatcher getMethodMatcher() {
|
|
|
|
- return this;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public boolean matches(Method method, Class<?> targetClass) {
|
|
|
|
- return matches(this.methodPrefix, method.getName());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public boolean isRuntime() {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public boolean matches(Method method, Class<?> targetClass, Object... args) {
|
|
|
|
- return matches(this.methodPrefix, method.getName());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private boolean matches(String mappedName, String methodName) {
|
|
|
|
- boolean equals = methodName.equals(mappedName);
|
|
|
|
- return equals || prefixMatches(mappedName, methodName) || suffixMatches(mappedName, methodName);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private boolean prefixMatches(String mappedName, String methodName) {
|
|
|
|
- return mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private boolean suffixMatches(String mappedName, String methodName) {
|
|
|
|
- return mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static class PointcutMatchingAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
|
|
|
-
|
|
|
|
- private final Map<Pointcut, AuthorizationManager<MethodInvocation>> managers;
|
|
|
|
-
|
|
|
|
- PointcutMatchingAuthorizationManager(Map<Pointcut, AuthorizationManager<MethodInvocation>> managers) {
|
|
|
|
- this.managers = managers;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation object) {
|
|
|
|
- for (Map.Entry<Pointcut, AuthorizationManager<MethodInvocation>> entry : this.managers.entrySet()) {
|
|
|
|
- Class<?> targetClass = (object.getThis() != null) ? AopUtils.getTargetClass(object.getThis()) : null;
|
|
|
|
- if (entry.getKey().getClassFilter().matches(targetClass)
|
|
|
|
- && entry.getKey().getMethodMatcher().matches(object.getMethod(), targetClass)) {
|
|
|
|
- return entry.getValue().check(authentication, object);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return new AuthorizationDecision(false);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static class MethodExpressionAuthorizationManager implements AuthorizationManager<MethodInvocation> {
|
|
|
|
-
|
|
|
|
- private final Expression expression;
|
|
|
|
-
|
|
|
|
- private SecurityExpressionHandler<MethodInvocation> expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
|
|
|
-
|
|
|
|
- MethodExpressionAuthorizationManager(Expression expression) {
|
|
|
|
- this.expression = expression;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation invocation) {
|
|
|
|
- EvaluationContext ctx = this.expressionHandler.createEvaluationContext(authentication, invocation);
|
|
|
|
- boolean granted = ExpressionUtils.evaluateAsBoolean(this.expression, ctx);
|
|
|
|
- return new ExpressionAuthorizationDecision(granted, this.expression);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- void setExpressionHandler(SecurityExpressionHandler<MethodInvocation> expressionHandler) {
|
|
|
|
- this.expressionHandler = expressionHandler;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
}
|
|
}
|