SEC-1562: Created SecurityExpressionHandler interface and AbstractSecurityExpressionHandler.

This commit is contained in:
Luke Taylor 2010-09-07 19:45:37 +01:00
parent b0998c01bc
commit af56f4844d
12 changed files with 161 additions and 136 deletions

View File

@ -3,4 +3,6 @@ dependencies {
compile project(':spring-security-core'),
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-context:$springVersion"
testCompile 'aopalliance:aopalliance:1.0'
}

View File

@ -0,0 +1,83 @@
package org.springframework.security.access.expression;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
/**
* Base implementation of the facade which isolates Spring Security's requirements for evaluating security expressions
* from the implementation of the underlying expression objects.
*
* @author Luke Taylor
* @since 3.1
*/
public abstract class AbstractSecurityExpressionHandler<T> implements SecurityExpressionHandler<T>, ApplicationContextAware {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private final ExpressionParser expressionParser = new SpelExpressionParser();
private final SecurityExpressionRootPropertyAccessor sxrpa = new SecurityExpressionRootPropertyAccessor();
private RoleHierarchy roleHierarchy;
private ApplicationContext applicationContext;
public final ExpressionParser getExpressionParser() {
return expressionParser;
}
/**
* Invokes the internal template methods to create {@code StandardEvaluationContext} and {@code SecurityExpressionRoot}
* objects. The root object will be injected with references to the application context, the {@code roleHierarchy}
* if set, and an {@code AuthenticationTrustResolver}.
*
* @param authentication the current authentication object
* @param invocation the invocation (filter, method, channel)
* @return the context object for use in evaluating the expression, populated with a suitable root object.
*/
public final EvaluationContext createEvaluationContext(Authentication authentication, T invocation) {
SecurityExpressionRoot root = createSecurityExpressionRoot(authentication, invocation);
root.setTrustResolver(trustResolver);
root.setRoleHierarchy(roleHierarchy);
root.setApplicationContext(applicationContext);
StandardEvaluationContext ctx = createEvaluationContextInternal(authentication, invocation);
ctx.addPropertyAccessor(sxrpa);
ctx.setRootObject(root);
return ctx;
}
/**
* Override to create a custom instance of {@code StandardEvaluationContext}.
* <p>
* The returned object will have a {@code SecurityExpressionRootPropertyAccessor} added, allowing beans in
* the {@code ApplicationContext} to be accessed via expression properties.
*
* @param authentication the current authentication object
* @param invocation the invocation (filter, method, channel)
* @return A {@code StandardEvaluationContext} or potentially a custom subclass if overridden.
*/
protected StandardEvaluationContext createEvaluationContextInternal(Authentication authentication, T invocation) {
return new StandardEvaluationContext();
}
/**
* Implement in order to create a root object of the correct type for the supported invocation type.
*
* @param authentication the current authentication object
* @param invocation the invocation (filter, method, channel)
* @return a
*/
protected abstract SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, T invocation);
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}

View File

@ -0,0 +1,25 @@
package org.springframework.security.access.expression;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.security.core.Authentication;
/**
* Facade which isolates Spring Security's requirements for evaluating security expressions
* from the implementation of the underlying expression objects
*
* @author Luke Taylor
* @since 3.1
*/
public interface SecurityExpressionHandler<T> extends AopInfrastructureBean {
/**
* @return an expression parser for the expressions used by the implementation.
*/
ExpressionParser getExpressionParser();
/**
* Provides an evaluation context in which to evaluate security expressions for the invocation type.
*/
EvaluationContext createEvaluationContext(Authentication authentication, T invocation);
}

View File

@ -1,71 +1,56 @@
package org.springframework.security.access.expression.method;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.*;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.PermissionCacheOptimizer;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.SecurityExpressionRootPropertyAccessor;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
/**
* The standard implementation of <tt>SecurityExpressionHandler</tt>.
* The standard implementation of {@code MethodSecurityExpressionHandler}.
* <p>
* A single instance should usually be shared amongst the beans that require expression support.
*
* @author Luke Taylor
* @since 3.0
*/
public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler, ApplicationContextAware {
public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpressionHandler<MethodInvocation> implements MethodSecurityExpressionHandler {
protected final Log logger = LogFactory.getLog(getClass());
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
private PermissionCacheOptimizer permissionCacheOptimizer = null;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private final SecurityExpressionRootPropertyAccessor sxrpa = new SecurityExpressionRootPropertyAccessor();
private final ExpressionParser expressionParser = new SpelExpressionParser();
private RoleHierarchy roleHierarchy;
private ApplicationContext applicationContext;
public DefaultMethodSecurityExpressionHandler() {
}
/**
* Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation and
* configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object.
* Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation.
*/
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(auth);
root.setTrustResolver(trustResolver);
root.setPermissionEvaluator(permissionEvaluator);
root.setRoleHierarchy(roleHierarchy);
root.setApplicationContext(applicationContext);
ctx.setRootObject(root);
ctx.addPropertyAccessor(sxrpa);
public StandardEvaluationContext createEvaluationContextInternal(Authentication auth, MethodInvocation mi) {
return new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
}
return ctx;
@Override
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(permissionEvaluator);
return root;
}
/**
@ -151,10 +136,6 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp
throw new IllegalArgumentException("Filter target must be a collection or array type, but was " + filterTarget);
}
public ExpressionParser getExpressionParser() {
return expressionParser;
}
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
@ -167,19 +148,7 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp
this.permissionCacheOptimizer = permissionCacheOptimizer;
}
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
this.trustResolver = trustResolver;
}
public void setReturnObject(Object returnObject, EvaluationContext ctx) {
((MethodSecurityExpressionRoot)ctx.getRootObject().getValue()).setReturnObject(returnObject);
}
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -17,7 +17,7 @@ import org.springframework.security.core.Authentication;
* Method pre-invocation handling based on expressions.
*
* @author Luke Taylor
* @since
* @since 3.0
*/
public class ExpressionBasedPreInvocationAdvice implements PreInvocationAuthorizationAdvice {
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();

View File

@ -1,30 +1,17 @@
package org.springframework.security.access.expression.method;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.security.core.Authentication;
import org.springframework.security.access.expression.SecurityExpressionHandler;
/**
* Facade which isolates Spring Security's requirements for evaluation method-security expressions
* from the implementation of the underlying expression objects.
* Extended expression-handler facade which adds methods which are specific to securing method invocations.
*
* @author Luke Taylor
* @since 3.0
*/
public interface MethodSecurityExpressionHandler extends AopInfrastructureBean {
/**
* @return an expression parser for the expressions used by the implementation.
*/
ExpressionParser getExpressionParser();
/**
* Provides an evaluation context in which to evaluate security expressions for a method invocation.
*/
EvaluationContext createEvaluationContext(Authentication authentication, MethodInvocation mi);
public interface MethodSecurityExpressionHandler extends SecurityExpressionHandler<MethodInvocation> {
/**
* Filters a target collection or array.
* Only applies to method invocations.
@ -33,7 +20,7 @@ public interface MethodSecurityExpressionHandler extends AopInfrastructureBean {
* @param filterExpression the expression which should be used as the filter condition. If it returns false on
* evaluation, the object will be removed from the returned collection
* @param ctx the current evaluation context (as created through a call to
* {@link #createEvaluationContext(Authentication, MethodInvocation)}
* {@link #createEvaluationContext(org.springframework.security.core.Authentication, Object)}
* @return the filtered collection or array
*/
Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx);
@ -44,7 +31,7 @@ public interface MethodSecurityExpressionHandler extends AopInfrastructureBean {
*
* @param returnObject the return object value
* @param ctx the context within which the object should be set (as created through a call to
* {@link #createEvaluationContext(Authentication, MethodInvocation)}
* {@link #createEvaluationContext(org.springframework.security.core.Authentication, Object)}
*/
void setReturnObject(Object returnObject, EvaluationContext ctx);

View File

@ -1,8 +1,7 @@
package org.springframework.security.taglibs.authz;
import java.io.IOException;
import java.util.Map;
import java.util.*;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@ -13,14 +12,15 @@ import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import org.springframework.context.ApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.expression.WebSecurityExpressionHandler;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
@ -64,8 +64,7 @@ public class AuthorizeTag extends LegacyAuthorizeTag {
}
private int authorizeUsingAccessExpression(Authentication currentUser) throws JspException {
// Get web expression
WebSecurityExpressionHandler handler = getExpressionHandler();
SecurityExpressionHandler<FilterInvocation> handler = getExpressionHandler();
Expression accessExpression;
try {
@ -105,17 +104,20 @@ public class AuthorizeTag extends LegacyAuthorizeTag {
this.var = var;
}
WebSecurityExpressionHandler getExpressionHandler() throws JspException {
SecurityExpressionHandler<FilterInvocation> getExpressionHandler() throws JspException {
ServletContext servletContext = pageContext.getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
Map<String, WebSecurityExpressionHandler> expressionHdlrs = ctx.getBeansOfType(WebSecurityExpressionHandler.class);
Map<String, SecurityExpressionHandler> expressionHdlrs = ctx.getBeansOfType(SecurityExpressionHandler.class);
if (expressionHdlrs.size() == 0) {
throw new JspException("No visible WebSecurityExpressionHandler instance could be found in the application " +
"context. There must be at least one in order to support expressions in JSP 'authorize' tags.");
for (SecurityExpressionHandler h : expressionHdlrs.values()) {
if (FilterInvocation.class.equals(GenericTypeResolver.resolveTypeArgument(h.getClass(), SecurityExpressionHandler.class))) {
return h;
}
}
return (WebSecurityExpressionHandler) expressionHdlrs.values().toArray()[0];
throw new JspException("No visible SecurityExpressionHandler<FilterInvocation> instance could be found in the " +
"application context. There must be at least one in order to support expressions in JSP 'authorize' tags.");
}
WebInvocationPrivilegeEvaluator getPrivilegeEvaluator() throws JspException {

View File

@ -5,6 +5,7 @@ dependencies {
project(':spring-security-web'),
project(':spring-security-acl'),
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-aop:$springVersion",
"org.springframework:spring-context:$springVersion",
"org.springframework:spring-expression:$springVersion",
"org.springframework:spring-web:$springVersion"

View File

@ -1,55 +1,19 @@
package org.springframework.security.web.access.expression;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.SecurityExpressionRootPropertyAccessor;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
/**
* Facade which isolates Spring Security's requirements for evaluating web-security expressions
* from the implementation of the underlying expression objects.
*
* @author Luke Taylor
* @since 3.0
*/
public class DefaultWebSecurityExpressionHandler implements WebSecurityExpressionHandler, ApplicationContextAware {
public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpressionHandler<FilterInvocation> {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private final ExpressionParser expressionParser = new SpelExpressionParser();
private final SecurityExpressionRootPropertyAccessor sxrpa = new SecurityExpressionRootPropertyAccessor();
private RoleHierarchy roleHierarchy;
private ApplicationContext applicationContext;
public ExpressionParser getExpressionParser() {
return expressionParser;
}
public EvaluationContext createEvaluationContext(Authentication authentication, FilterInvocation fi) {
SecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
root.setTrustResolver(trustResolver);
root.setRoleHierarchy(roleHierarchy);
root.setApplicationContext(applicationContext);
StandardEvaluationContext ctx = new StandardEvaluationContext(root);
ctx.addPropertyAccessor(sxrpa);
return ctx;
}
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
@Override
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
return new WebSecurityExpressionRoot(authentication, fi);
}
}

View File

@ -10,12 +10,14 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.RequestMatcher;
import org.springframework.util.Assert;
/**
* Expression-based <tt>FilterInvocationSecurityMetadataSource</tt>.
* Expression-based {@code FilterInvocationSecurityMetadataSource}.
*
* @author Luke Taylor
* @since 3.0
@ -25,7 +27,7 @@ public final class ExpressionBasedFilterInvocationSecurityMetadataSource extends
public ExpressionBasedFilterInvocationSecurityMetadataSource(
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap,
WebSecurityExpressionHandler expressionHandler) {
SecurityExpressionHandler<FilterInvocation> expressionHandler) {
super(processMap(requestMap, expressionHandler.getExpressionParser()));
Assert.notNull(expressionHandler, "A non-null SecurityExpressionHandler is required");
}

View File

@ -6,6 +6,7 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
@ -15,7 +16,7 @@ import org.springframework.security.web.FilterInvocation;
* @since 3.0
*/
public class WebExpressionVoter implements AccessDecisionVoter {
private WebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
private SecurityExpressionHandler<FilterInvocation> expressionHandler = new DefaultWebSecurityExpressionHandler();
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
assert authentication != null;
@ -52,7 +53,7 @@ public class WebExpressionVoter implements AccessDecisionVoter {
return clazz.isAssignableFrom(FilterInvocation.class);
}
public void setExpressionHandler(WebSecurityExpressionHandler expressionHandler) {
public void setExpressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
this.expressionHandler = expressionHandler;
}
}

View File

@ -1,19 +1,8 @@
package org.springframework.security.web.access.expression;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.security.core.Authentication;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.web.FilterInvocation;
public interface WebSecurityExpressionHandler {
/**
* @return an expression parser for the expressions used by the implementation.
*/
ExpressionParser getExpressionParser();
/**
* Provides an evaluation context in which to evaluate security expressions for a web invocation.
*/
EvaluationContext createEvaluationContext(Authentication authentication, FilterInvocation fi);
@Deprecated
public interface WebSecurityExpressionHandler extends SecurityExpressionHandler<FilterInvocation> {
}