SEC-1294: Enable access to beans from ApplicationContext in EL expressions.
ExpressionHandlers are now ApplicationContextAware and set the app context on the SecurityExpressionRoot. A custom PropertyAccessor resolves the properties against the root by looking them up in the app context.
This commit is contained in:
+10
@@ -4,6 +4,7 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -22,6 +23,7 @@ public abstract class SecurityExpressionRoot {
|
||||
private AuthenticationTrustResolver trustResolver;
|
||||
private RoleHierarchy roleHierarchy;
|
||||
private Set<String> roles;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/** Allows "permitAll" expression */
|
||||
public final boolean permitAll = true;
|
||||
@@ -92,6 +94,14 @@ public abstract class SecurityExpressionRoot {
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
ApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
private Set<String> getAuthoritySet() {
|
||||
if (roles == null) {
|
||||
roles = new HashSet<String>();
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.springframework.security.access.expression;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class SecurityExpressionRootPropertyAccessor implements PropertyAccessor {
|
||||
public Class[] CLASSES = {SecurityExpressionRoot.class};
|
||||
|
||||
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
ApplicationContext ctx = ((SecurityExpressionRoot)target).getApplicationContext();
|
||||
|
||||
if (ctx == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ctx.containsBean(name);
|
||||
}
|
||||
|
||||
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return new TypedValue(((SecurityExpressionRoot)target).getApplicationContext().getBean(name));
|
||||
}
|
||||
|
||||
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
|
||||
}
|
||||
|
||||
public Class[] getSpecificTargetClasses() {
|
||||
return CLASSES;
|
||||
}
|
||||
|
||||
}
|
||||
+13
-1
@@ -9,6 +9,9 @@ import java.util.List;
|
||||
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;
|
||||
@@ -18,6 +21,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.security.access.PermissionCacheOptimizer;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.expression.ExpressionUtils;
|
||||
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;
|
||||
@@ -31,7 +35,7 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {
|
||||
public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler, ApplicationContextAware {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -39,8 +43,10 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp
|
||||
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
|
||||
private PermissionCacheOptimizer permissionCacheOptimizer = null;
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
private final SecurityExpressionRootPropertyAccessor sxrpa = new SecurityExpressionRootPropertyAccessor();
|
||||
private ExpressionParser expressionParser = new SpelExpressionParser();
|
||||
private RoleHierarchy roleHierarchy;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public DefaultMethodSecurityExpressionHandler() {
|
||||
}
|
||||
@@ -55,7 +61,9 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp
|
||||
root.setTrustResolver(trustResolver);
|
||||
root.setPermissionEvaluator(permissionEvaluator);
|
||||
root.setRoleHierarchy(roleHierarchy);
|
||||
root.setApplicationContext(applicationContext);
|
||||
ctx.setRootObject(root);
|
||||
ctx.addPropertyAccessor(sxrpa);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
@@ -170,4 +178,8 @@ public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExp
|
||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
+22
-2
@@ -6,6 +6,8 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
@@ -23,8 +25,9 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||
private static Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class);
|
||||
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer;
|
||||
private final MethodInvocation mi;
|
||||
private ApplicationContext appContext;
|
||||
private boolean argumentsAdded;
|
||||
private MethodInvocation mi;
|
||||
|
||||
/**
|
||||
* Intended for testing. Don't use in practice as it creates a new parameter resolver
|
||||
@@ -44,6 +47,7 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||
@Override
|
||||
public Object lookupVariable(String name) {
|
||||
Object variable = super.lookupVariable(name);
|
||||
|
||||
if (variable != null) {
|
||||
return variable;
|
||||
}
|
||||
@@ -53,7 +57,23 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||
argumentsAdded = true;
|
||||
}
|
||||
|
||||
return super.lookupVariable(name);
|
||||
variable = super.lookupVariable(name);
|
||||
|
||||
if (variable != null) {
|
||||
return variable;
|
||||
}
|
||||
|
||||
if (appContext != null) {
|
||||
try {
|
||||
super.setVariable(name, appContext.getBean(name));
|
||||
|
||||
return super.lookupVariable(name);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
logger.debug("Bean lookup for variable '" + name + "' failed");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
|
||||
|
||||
+6
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.access.prepost.PreFilter;
|
||||
|
||||
|
||||
@@ -43,4 +44,9 @@ public class ExpressionProtectedBusinessServiceImpl implements BusinessService {
|
||||
public Object[] methodReturningAnArray(Object[] someArray) {
|
||||
return someArray;
|
||||
}
|
||||
|
||||
@PreAuthorize("#x == 'x' and number.intValue() == 1294 ")
|
||||
public void methodWithBeanNamePropertyAccessExpression(String x) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user