SEC-1887: Improve extensibility of expression-based security classes

Introduces a new SecurityExpressionOperations interface which is
implemented by SecurityExpressionRoot
This commit is contained in:
Andrei Stefan 2012-01-20 02:48:36 +02:00 committed by Luke Taylor
parent b493afa18c
commit 0f9ee81df1
6 changed files with 118 additions and 30 deletions

View File

@ -10,8 +10,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy; 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.core.Authentication;
/** /**
@ -22,7 +20,6 @@ import org.springframework.security.core.Authentication;
* @since 3.1 * @since 3.1
*/ */
public abstract class AbstractSecurityExpressionHandler<T> implements SecurityExpressionHandler<T>, ApplicationContextAware { public abstract class AbstractSecurityExpressionHandler<T> implements SecurityExpressionHandler<T>, ApplicationContextAware {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private final ExpressionParser expressionParser = new SpelExpressionParser(); private final ExpressionParser expressionParser = new SpelExpressionParser();
private BeanResolver br; private BeanResolver br;
private RoleHierarchy roleHierarchy; private RoleHierarchy roleHierarchy;
@ -34,17 +31,14 @@ public abstract class AbstractSecurityExpressionHandler<T> implements SecurityEx
/** /**
* Invokes the internal template methods to create {@code StandardEvaluationContext} and {@code SecurityExpressionRoot} * 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} * objects.
* if set, and an {@code AuthenticationTrustResolver}.
* *
* @param authentication the current authentication object * @param authentication the current authentication object
* @param invocation the invocation (filter, method, channel) * @param invocation the invocation (filter, method, channel)
* @return the context object for use in evaluating the expression, populated with a suitable root object. * @return the context object for use in evaluating the expression, populated with a suitable root object.
*/ */
public final EvaluationContext createEvaluationContext(Authentication authentication, T invocation) { public final EvaluationContext createEvaluationContext(Authentication authentication, T invocation) {
SecurityExpressionRoot root = createSecurityExpressionRoot(authentication, invocation); SecurityExpressionOperations root = createSecurityExpressionRoot(authentication, invocation);
root.setTrustResolver(trustResolver);
root.setRoleHierarchy(roleHierarchy);
StandardEvaluationContext ctx = createEvaluationContextInternal(authentication, invocation); StandardEvaluationContext ctx = createEvaluationContextInternal(authentication, invocation);
ctx.setBeanResolver(br); ctx.setBeanResolver(br);
ctx.setRootObject(root); ctx.setRootObject(root);
@ -73,7 +67,11 @@ public abstract class AbstractSecurityExpressionHandler<T> implements SecurityEx
* @param invocation the invocation (filter, method, channel) * @param invocation the invocation (filter, method, channel)
* @return the object wh * @return the object wh
*/ */
protected abstract SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, T invocation); protected abstract SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, T invocation);
protected RoleHierarchy getRoleHierarchy() {
return roleHierarchy;
}
public void setRoleHierarchy(RoleHierarchy roleHierarchy) { public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy; this.roleHierarchy = roleHierarchy;

View File

@ -0,0 +1,30 @@
package org.springframework.security.access.expression;
public interface SecurityExpressionOperations {
public abstract boolean hasAuthority(String authority);
public abstract boolean hasAnyAuthority(String... authorities);
public abstract boolean hasRole(String role);
public abstract boolean hasAnyRole(String... roles);
public abstract boolean permitAll();
public abstract boolean denyAll();
public abstract boolean isAnonymous();
public abstract boolean isAuthenticated();
public abstract boolean isRememberMe();
public abstract boolean isFullyAuthenticated();
public abstract boolean hasPermission(Object target, Object permission);
public abstract boolean hasPermission(Object targetId, String targetType,
Object permission);
}

View File

@ -20,7 +20,7 @@ import org.springframework.security.core.authority.AuthorityUtils;
* @author Luke Taylor * @author Luke Taylor
* @since 3.0 * @since 3.0
*/ */
public abstract class SecurityExpressionRoot { public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
protected final Authentication authentication; protected final Authentication authentication;
private AuthenticationTrustResolver trustResolver; private AuthenticationTrustResolver trustResolver;
private RoleHierarchy roleHierarchy; private RoleHierarchy roleHierarchy;
@ -45,18 +45,34 @@ public abstract class SecurityExpressionRoot {
this.authentication = a; this.authentication = a;
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasAuthority(java.lang.String)
*/
@Override
public final boolean hasAuthority(String authority) { public final boolean hasAuthority(String authority) {
return hasRole(authority); return hasRole(authority);
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasAnyAuthority(java.lang.String)
*/
@Override
public final boolean hasAnyAuthority(String... authorities) { public final boolean hasAnyAuthority(String... authorities) {
return hasAnyRole(authorities); return hasAnyRole(authorities);
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasRole(java.lang.String)
*/
@Override
public final boolean hasRole(String role) { public final boolean hasRole(String role) {
return getAuthoritySet().contains(role); return getAuthoritySet().contains(role);
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasAnyRole(java.lang.String)
*/
@Override
public final boolean hasAnyRole(String... roles) { public final boolean hasAnyRole(String... roles) {
Set<String> roleSet = getAuthoritySet(); Set<String> roleSet = getAuthoritySet();
@ -73,26 +89,50 @@ public abstract class SecurityExpressionRoot {
return authentication; return authentication;
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#permitAll()
*/
@Override
public final boolean permitAll() { public final boolean permitAll() {
return true; return true;
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#denyAll()
*/
@Override
public final boolean denyAll() { public final boolean denyAll() {
return false; return false;
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isAnonymous()
*/
@Override
public final boolean isAnonymous() { public final boolean isAnonymous() {
return trustResolver.isAnonymous(authentication); return trustResolver.isAnonymous(authentication);
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isAuthenticated()
*/
@Override
public final boolean isAuthenticated() { public final boolean isAuthenticated() {
return !isAnonymous(); return !isAnonymous();
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isRememberMe()
*/
@Override
public final boolean isRememberMe() { public final boolean isRememberMe() {
return trustResolver.isRememberMe(authentication); return trustResolver.isRememberMe(authentication);
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isFullyAuthenticated()
*/
@Override
public final boolean isFullyAuthenticated() { public final boolean isFullyAuthenticated() {
return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication); return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication);
} }
@ -124,10 +164,18 @@ public abstract class SecurityExpressionRoot {
return roles; return roles;
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasPermission(java.lang.Object, java.lang.Object)
*/
@Override
public boolean hasPermission(Object target, Object permission) { public boolean hasPermission(Object target, Object permission) {
return permissionEvaluator.hasPermission(authentication, target, permission); return permissionEvaluator.hasPermission(authentication, target, permission);
} }
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasPermission(java.lang.Object, java.lang.String, java.lang.Object)
*/
@Override
public boolean hasPermission(Object targetId, String targetType, Object permission) { public boolean hasPermission(Object targetId, String targetType, Object permission) {
return permissionEvaluator.hasPermission(authentication, (Serializable)targetId, targetType, permission); return permissionEvaluator.hasPermission(authentication, (Serializable)targetId, targetType, permission);
} }

View File

@ -1,7 +1,10 @@
package org.springframework.security.access.expression.method; package org.springframework.security.access.expression.method;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation; import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -12,11 +15,11 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.PermissionCacheOptimizer; 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.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.DenyAllPermissionEvaluator;
import org.springframework.security.access.expression.ExpressionUtils; import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
/** /**
@ -31,6 +34,7 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
protected final Log logger = LogFactory.getLog(getClass()); protected final Log logger = LogFactory.getLog(getClass());
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private PermissionCacheOptimizer permissionCacheOptimizer = null; private PermissionCacheOptimizer permissionCacheOptimizer = null;
@ -45,10 +49,12 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
} }
@Override @Override
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) { protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication); MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
root.setThis(invocation.getThis()); root.setThis(invocation.getThis());
root.setPermissionEvaluator(getPermissionEvaluator()); root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root; return root;
} }

View File

@ -23,7 +23,7 @@ public class AbstractSecurityExpressionHandlerTests {
public void setUp() throws Exception { public void setUp() throws Exception {
handler = new AbstractSecurityExpressionHandler<Object>() { handler = new AbstractSecurityExpressionHandler<Object>() {
@Override @Override
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, Object o) { protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, Object o) {
return new SecurityExpressionRoot(authentication) {}; return new SecurityExpressionRoot(authentication) {};
} }
}; };

View File

@ -1,7 +1,9 @@
package org.springframework.security.web.access.expression; package org.springframework.security.web.access.expression;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler; import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.FilterInvocation;
@ -12,10 +14,14 @@ import org.springframework.security.web.FilterInvocation;
*/ */
public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpressionHandler<FilterInvocation> { public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpressionHandler<FilterInvocation> {
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@Override @Override
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) { protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi); WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
root.setPermissionEvaluator(getPermissionEvaluator()); root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root; return root;
} }
} }