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.security.access.PermissionEvaluator;
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;
/**
@ -22,7 +20,6 @@ import org.springframework.security.core.Authentication;
* @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 BeanResolver br;
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}
* objects. The root object will be injected with references to the application context, the {@code roleHierarchy}
* if set, and an {@code AuthenticationTrustResolver}.
* objects.
*
* @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);
SecurityExpressionOperations root = createSecurityExpressionRoot(authentication, invocation);
StandardEvaluationContext ctx = createEvaluationContextInternal(authentication, invocation);
ctx.setBeanResolver(br);
ctx.setRootObject(root);
@ -73,8 +67,12 @@ public abstract class AbstractSecurityExpressionHandler<T> implements SecurityEx
* @param invocation the invocation (filter, method, channel)
* @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) {
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
* @since 3.0
*/
public abstract class SecurityExpressionRoot {
public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
protected final Authentication authentication;
private AuthenticationTrustResolver trustResolver;
private RoleHierarchy roleHierarchy;
@ -45,19 +45,35 @@ public abstract class SecurityExpressionRoot {
this.authentication = a;
}
public final boolean hasAuthority(String authority) {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasAuthority(java.lang.String)
*/
@Override
public final boolean hasAuthority(String authority) {
return hasRole(authority);
}
public final boolean hasAnyAuthority(String... authorities) {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasAnyAuthority(java.lang.String)
*/
@Override
public final boolean hasAnyAuthority(String... authorities) {
return hasAnyRole(authorities);
}
public final boolean hasRole(String role) {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasRole(java.lang.String)
*/
@Override
public final boolean hasRole(String role) {
return getAuthoritySet().contains(role);
}
public final boolean hasAnyRole(String... roles) {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasAnyRole(java.lang.String)
*/
@Override
public final boolean hasAnyRole(String... roles) {
Set<String> roleSet = getAuthoritySet();
for (String role : roles) {
@ -73,27 +89,51 @@ public abstract class SecurityExpressionRoot {
return authentication;
}
public final boolean permitAll() {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#permitAll()
*/
@Override
public final boolean permitAll() {
return true;
}
public final boolean denyAll() {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#denyAll()
*/
@Override
public final boolean denyAll() {
return false;
}
public final boolean isAnonymous() {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isAnonymous()
*/
@Override
public final boolean isAnonymous() {
return trustResolver.isAnonymous(authentication);
}
public final boolean isAuthenticated() {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isAuthenticated()
*/
@Override
public final boolean isAuthenticated() {
return !isAnonymous();
}
public final boolean isRememberMe() {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isRememberMe()
*/
@Override
public final boolean isRememberMe() {
return trustResolver.isRememberMe(authentication);
}
public final boolean isFullyAuthenticated() {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#isFullyAuthenticated()
*/
@Override
public final boolean isFullyAuthenticated() {
return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication);
}
@ -124,11 +164,19 @@ public abstract class SecurityExpressionRoot {
return roles;
}
public boolean hasPermission(Object target, Object permission) {
/* (non-Javadoc)
* @see org.springframework.security.access.expression.SecurityExpressionOperations#hasPermission(java.lang.Object, java.lang.Object)
*/
@Override
public boolean hasPermission(Object target, Object permission) {
return permissionEvaluator.hasPermission(authentication, target, permission);
}
public boolean hasPermission(Object targetId, String targetType, Object 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) {
return permissionEvaluator.hasPermission(authentication, (Serializable)targetId, targetType, permission);
}

View File

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

View File

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

View File

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