Polish AOP Structure

- Changed from MethodMatcher to Pointcut since authorization
annotations also can be attached to classes
- Adjusted advice to extend Before or AfterAdvice
- Adjusted advice to extend PointcutAdvisor so
that it can share its Pointcut
- Adjusted advice to extend AopInfrastructureBean to
align with old advice classes

Issue gh-9289
This commit is contained in:
Josh Cummings
2021-04-08 10:07:09 -06:00
parent 62d77ec97e
commit 2b494ebc5f
17 changed files with 266 additions and 218 deletions

View File

@@ -19,6 +19,7 @@ package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
@@ -31,24 +32,24 @@ import org.springframework.util.Assert;
*
* @param <T> the type of object that the authorization check is being done one.
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class AuthorizationManagerMethodAfterAdvice<T> implements AuthorizationMethodAfterAdvice<T> {
private final MethodMatcher methodMatcher;
private final Pointcut pointcut;
private final AuthorizationManager<T> authorizationManager;
/**
* Creates an instance.
* @param methodMatcher the {@link MethodMatcher} to use
* @param pointcut the {@link Pointcut} to use
* @param authorizationManager the {@link AuthorizationManager} to use
*/
public AuthorizationManagerMethodAfterAdvice(MethodMatcher methodMatcher,
AuthorizationManager<T> authorizationManager) {
Assert.notNull(methodMatcher, "methodMatcher cannot be null");
public AuthorizationManagerMethodAfterAdvice(Pointcut pointcut, AuthorizationManager<T> authorizationManager) {
Assert.notNull(pointcut, "pointcut cannot be null");
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
this.methodMatcher = methodMatcher;
this.pointcut = pointcut;
this.authorizationManager = authorizationManager;
}
@@ -65,9 +66,12 @@ public final class AuthorizationManagerMethodAfterAdvice<T> implements Authoriza
return returnedObject;
}
/**
* {@inheritDoc}
*/
@Override
public MethodMatcher getMethodMatcher() {
return this.methodMatcher;
public Pointcut getPointcut() {
return this.pointcut;
}
}

View File

@@ -19,6 +19,7 @@ package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
@@ -31,24 +32,24 @@ import org.springframework.util.Assert;
*
* @param <T> the type of object that the authorization check is being done one.
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class AuthorizationManagerMethodBeforeAdvice<T> implements AuthorizationMethodBeforeAdvice<T> {
private final MethodMatcher methodMatcher;
private final Pointcut pointcut;
private final AuthorizationManager<T> authorizationManager;
/**
* Creates an instance.
* @param methodMatcher the {@link MethodMatcher} to use
* @param pointcut the {@link Pointcut} to use
* @param authorizationManager the {@link AuthorizationManager} to use
*/
public AuthorizationManagerMethodBeforeAdvice(MethodMatcher methodMatcher,
AuthorizationManager<T> authorizationManager) {
Assert.notNull(methodMatcher, "methodMatcher cannot be null");
public AuthorizationManagerMethodBeforeAdvice(Pointcut pointcut, AuthorizationManager<T> authorizationManager) {
Assert.notNull(pointcut, "pointcut cannot be null");
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
this.methodMatcher = methodMatcher;
this.pointcut = pointcut;
this.authorizationManager = authorizationManager;
}
@@ -64,9 +65,12 @@ public final class AuthorizationManagerMethodBeforeAdvice<T> implements Authoriz
this.authorizationManager.verify(authentication, object);
}
/**
* {@inheritDoc}
*/
@Override
public MethodMatcher getMethodMatcher() {
return this.methodMatcher;
public Pointcut getPointcut() {
return this.pointcut;
}
}

View File

@@ -18,30 +18,40 @@ package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.Pointcut;
import org.springframework.aop.AfterAdvice;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.security.core.Authentication;
/**
* An Authorization advice that can determine if an {@link Authentication} has access to
* the returned object from the {@link MethodInvocation}. The {@link #getMethodMatcher()}
* An {@link Advice} which can determine if an {@link Authentication} has
* access to the returned object from the {@link MethodInvocation}. {@link #getPointcut()}
* describes when the advice applies for the method.
*
* @param <T> the type of object that the authorization check is being done one.
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public interface AuthorizationMethodAfterAdvice<T> extends Pointcut {
public interface AuthorizationMethodAfterAdvice<T> extends AfterAdvice, PointcutAdvisor, AopInfrastructureBean {
/**
* Returns the default {@link ClassFilter}.
* @return the {@link ClassFilter#TRUE} to use
* {@inheritDoc}
*/
@Override
default ClassFilter getClassFilter() {
return ClassFilter.TRUE;
default boolean isPerInstance() {
return true;
}
/**
* {@inheritDoc}
*/
@Override
default Advice getAdvice() {
return this;
}
/**

View File

@@ -18,28 +18,38 @@ package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.Pointcut;
import org.aopalliance.aop.Advice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.security.core.Authentication;
/**
* An advice which can determine if an {@link Authentication} has access to the {@link T}
* object. The {@link #getMethodMatcher()} describes when the advice applies for the
* method.
* An {@link Advice} which can determine if an {@link Authentication} has access to the
* {@link T} object. {@link #getPointcut()} describes when the advice applies.
*
* @param <T> the type of object that the authorization check is being done one.
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public interface AuthorizationMethodBeforeAdvice<T> extends Pointcut {
public interface AuthorizationMethodBeforeAdvice<T> extends BeforeAdvice, PointcutAdvisor, AopInfrastructureBean {
/**
* Returns the default {@link ClassFilter}.
* @return the {@link ClassFilter#TRUE} to use
* {@inheritDoc}
*/
@Override
default ClassFilter getClassFilter() {
return ClassFilter.TRUE;
default boolean isPerInstance() {
return true;
}
/**
* {@inheritDoc}
*/
@Override
default Advice getAdvice() {
return this;
}
/**

View File

@@ -16,7 +16,6 @@
package org.springframework.security.authorization.method;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.Supplier;
@@ -24,10 +23,11 @@ import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.core.log.LogMessage;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* An {@link AuthorizationMethodAfterAdvice} which delegates to specific
@@ -35,6 +35,7 @@ import org.springframework.security.core.Authentication;
* the {@link MethodInvocation}.
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class DelegatingAuthorizationMethodAfterAdvice
@@ -42,18 +43,7 @@ public final class DelegatingAuthorizationMethodAfterAdvice
private final Log logger = LogFactory.getLog(getClass());
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
for (AuthorizationMethodAfterAdvice<MethodAuthorizationContext> delegate : DelegatingAuthorizationMethodAfterAdvice.this.delegates) {
MethodMatcher methodMatcher = delegate.getMethodMatcher();
if (methodMatcher.matches(method, targetClass)) {
return true;
}
}
return false;
}
};
private final Pointcut pointcut;
private final List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates;
@@ -63,12 +53,26 @@ public final class DelegatingAuthorizationMethodAfterAdvice
*/
public DelegatingAuthorizationMethodAfterAdvice(
List<AuthorizationMethodAfterAdvice<MethodAuthorizationContext>> delegates) {
Assert.notEmpty(delegates, "delegates cannot be empty");
this.delegates = delegates;
ComposablePointcut pointcut = null;
for (AuthorizationMethodAfterAdvice<?> advice : delegates) {
if (pointcut == null) {
pointcut = new ComposablePointcut(advice.getPointcut());
}
else {
pointcut.union(advice.getPointcut());
}
}
this.pointcut = pointcut;
}
/**
* {@inheritDoc}
*/
@Override
public MethodMatcher getMethodMatcher() {
return this.methodMatcher;
public Pointcut getPointcut() {
return this.pointcut;
}
/**

View File

@@ -16,17 +16,17 @@
package org.springframework.security.authorization.method;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.core.log.LogMessage;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* An {@link AuthorizationMethodBeforeAdvice} which delegates to a specific
@@ -35,6 +35,7 @@ import org.springframework.security.core.Authentication;
* one of the {@link AuthorizationMethodBeforeAdvice}s denied.
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class DelegatingAuthorizationMethodBeforeAdvice
@@ -42,18 +43,7 @@ public final class DelegatingAuthorizationMethodBeforeAdvice
private final Log logger = LogFactory.getLog(getClass());
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
for (AuthorizationMethodBeforeAdvice<MethodAuthorizationContext> delegate : DelegatingAuthorizationMethodBeforeAdvice.this.delegates) {
MethodMatcher methodMatcher = delegate.getMethodMatcher();
if (methodMatcher.matches(method, targetClass)) {
return true;
}
}
return false;
}
};
private final Pointcut pointcut;
private final List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates;
@@ -63,12 +53,26 @@ public final class DelegatingAuthorizationMethodBeforeAdvice
*/
public DelegatingAuthorizationMethodBeforeAdvice(
List<AuthorizationMethodBeforeAdvice<MethodAuthorizationContext>> delegates) {
Assert.notEmpty(delegates, "delegates cannot be empty");
this.delegates = delegates;
ComposablePointcut pointcut = null;
for (AuthorizationMethodBeforeAdvice<?> advice : delegates) {
if (pointcut == null) {
pointcut = new ComposablePointcut(advice.getPointcut());
}
else {
pointcut.union(advice.getPointcut());
}
}
this.pointcut = pointcut;
}
/**
* {@inheritDoc}
*/
@Override
public MethodMatcher getMethodMatcher() {
return this.methodMatcher;
public Pointcut getPointcut() {
return this.pointcut;
}
/**

View File

@@ -21,9 +21,8 @@ import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
@@ -40,6 +39,7 @@ import org.springframework.util.Assert;
* {@link PostFilter} annotation.
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class PostFilterAuthorizationMethodAfterAdvice
@@ -47,16 +47,19 @@ public final class PostFilterAuthorizationMethodAfterAdvice
private final PostFilterExpressionAttributeRegistry registry = new PostFilterExpressionAttributeRegistry();
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return PostFilterAuthorizationMethodAfterAdvice.this.registry.getAttribute(method,
targetClass) != ExpressionAttribute.NULL_ATTRIBUTE;
}
};
private final Pointcut pointcut;
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
/**
* Create a {@link PostFilterAuthorizationMethodAfterAdvice} using the provided
* parameters
* @param pointcut the {@link Pointcut} for when this advice applies
*/
public PostFilterAuthorizationMethodAfterAdvice(Pointcut pointcut) {
this.pointcut = pointcut;
}
/**
* Sets the {@link MethodSecurityExpressionHandler}.
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
@@ -66,9 +69,12 @@ public final class PostFilterAuthorizationMethodAfterAdvice
this.expressionHandler = expressionHandler;
}
/**
* {@inheritDoc}
*/
@Override
public MethodMatcher getMethodMatcher() {
return this.methodMatcher;
public Pointcut getPointcut() {
return this.pointcut;
}
/**

View File

@@ -21,9 +21,8 @@ import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
@@ -40,6 +39,7 @@ import org.springframework.util.StringUtils;
* evaluating an expression from the {@link PreFilter} annotation.
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.5
*/
public final class PreFilterAuthorizationMethodBeforeAdvice
@@ -47,16 +47,19 @@ public final class PreFilterAuthorizationMethodBeforeAdvice
private final PreFilterExpressionAttributeRegistry registry = new PreFilterExpressionAttributeRegistry();
private final MethodMatcher methodMatcher = new StaticMethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return PreFilterAuthorizationMethodBeforeAdvice.this.registry.getAttribute(method,
targetClass) != PreFilterExpressionAttribute.NULL_ATTRIBUTE;
}
};
private final Pointcut pointcut;
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
/**
* Create a {@link PreFilterAuthorizationMethodBeforeAdvice} using the provided
* parameters
* @param pointcut the {@link Pointcut} for when this advice applies
*/
public PreFilterAuthorizationMethodBeforeAdvice(Pointcut pointcut) {
this.pointcut = pointcut;
}
/**
* Sets the {@link MethodSecurityExpressionHandler}.
* @param expressionHandler the {@link MethodSecurityExpressionHandler} to use
@@ -66,9 +69,12 @@ public final class PreFilterAuthorizationMethodBeforeAdvice
this.expressionHandler = expressionHandler;
}
/**
* {@inheritDoc}
*/
@Override
public MethodMatcher getMethodMatcher() {
return this.methodMatcher;
public Pointcut getPointcut() {
return this.pointcut;
}
/**