diff --git a/core/src/main/java/org/springframework/security/access/expression/AbstractSecurityExpressionHandler.java b/core/src/main/java/org/springframework/security/access/expression/AbstractSecurityExpressionHandler.java index 39bf647d8f..a48801e9e2 100644 --- a/core/src/main/java/org/springframework/security/access/expression/AbstractSecurityExpressionHandler.java +++ b/core/src/main/java/org/springframework/security/access/expression/AbstractSecurityExpressionHandler.java @@ -8,6 +8,7 @@ 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.PermissionEvaluator; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; @@ -25,6 +26,7 @@ public abstract class AbstractSecurityExpressionHandler implements SecurityEx private final ExpressionParser expressionParser = new SpelExpressionParser(); private BeanResolver br; private RoleHierarchy roleHierarchy; + private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator(); public final ExpressionParser getExpressionParser() { return expressionParser; @@ -77,6 +79,14 @@ public abstract class AbstractSecurityExpressionHandler implements SecurityEx this.roleHierarchy = roleHierarchy; } + protected PermissionEvaluator getPermissionEvaluator() { + return permissionEvaluator; + } + + public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) { + this.permissionEvaluator = permissionEvaluator; + } + public void setApplicationContext(ApplicationContext applicationContext) { br = new BeanFactoryResolver(applicationContext); } diff --git a/core/src/main/java/org/springframework/security/access/expression/method/DenyAllPermissionEvaluator.java b/core/src/main/java/org/springframework/security/access/expression/DenyAllPermissionEvaluator.java similarity index 90% rename from core/src/main/java/org/springframework/security/access/expression/method/DenyAllPermissionEvaluator.java rename to core/src/main/java/org/springframework/security/access/expression/DenyAllPermissionEvaluator.java index 0c1783d0fc..75d3702672 100644 --- a/core/src/main/java/org/springframework/security/access/expression/method/DenyAllPermissionEvaluator.java +++ b/core/src/main/java/org/springframework/security/access/expression/DenyAllPermissionEvaluator.java @@ -1,4 +1,4 @@ -package org.springframework.security.access.expression.method; +package org.springframework.security.access.expression; import java.io.Serializable; @@ -14,7 +14,7 @@ import org.springframework.security.core.Authentication; * @author Luke Taylor * @since 3.0 */ -class DenyAllPermissionEvaluator implements PermissionEvaluator { +public class DenyAllPermissionEvaluator implements PermissionEvaluator { private final Log logger = LogFactory.getLog(getClass()); diff --git a/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java b/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java index ce788dc1a5..6de580206d 100644 --- a/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java +++ b/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java @@ -14,6 +14,7 @@ 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.core.Authentication; @@ -31,7 +32,6 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr protected final Log logger = LogFactory.getLog(getClass()); private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); - private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator(); private PermissionCacheOptimizer permissionCacheOptimizer = null; public DefaultMethodSecurityExpressionHandler() { @@ -48,7 +48,7 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) { MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication); root.setThis(invocation.getThis()); - root.setPermissionEvaluator(permissionEvaluator); + root.setPermissionEvaluator(getPermissionEvaluator()); return root; } @@ -140,10 +140,6 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr this.parameterNameDiscoverer = parameterNameDiscoverer; } - public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) { - this.permissionEvaluator = permissionEvaluator; - } - public void setPermissionCacheOptimizer(PermissionCacheOptimizer permissionCacheOptimizer) { this.permissionCacheOptimizer = permissionCacheOptimizer; } diff --git a/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java b/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java index 72c0321af6..1be1457bc6 100644 --- a/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java +++ b/core/src/main/java/org/springframework/security/access/expression/method/MethodSecurityEvaluationContext.java @@ -7,8 +7,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.AopProxyUtils; 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; @@ -27,7 +25,6 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext { private ParameterNameDiscoverer parameterNameDiscoverer; private final MethodInvocation mi; - private ApplicationContext appContext; private boolean argumentsAdded; /** @@ -64,16 +61,6 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext { 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; } diff --git a/taglibs/src/main/java/org/springframework/security/taglibs/authz/AbstractAuthorizeTag.java b/taglibs/src/main/java/org/springframework/security/taglibs/authz/AbstractAuthorizeTag.java index 9d82fc4796..4cea18aa87 100644 --- a/taglibs/src/main/java/org/springframework/security/taglibs/authz/AbstractAuthorizeTag.java +++ b/taglibs/src/main/java/org/springframework/security/taglibs/authz/AbstractAuthorizeTag.java @@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.context.ApplicationContext; import org.springframework.core.GenericTypeResolver; +import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ParseException; import org.springframework.security.access.expression.ExpressionUtils; @@ -161,8 +162,7 @@ public abstract class AbstractAuthorizeTag { * @throws IOException */ public boolean authorizeUsingAccessExpression() throws IOException { - Authentication currentUser = SecurityContextHolder.getContext().getAuthentication(); - if (currentUser == null) { + if (SecurityContextHolder.getContext().getAuthentication() == null) { return false; } @@ -178,13 +178,20 @@ public abstract class AbstractAuthorizeTag { throw ioException; } + return ExpressionUtils.evaluateAsBoolean(accessExpression, createExpressionEvaluationContext(handler)); + } + + /** + * Allows the {@code EvaluationContext} to be customized for variable lookup etc. + */ + protected EvaluationContext createExpressionEvaluationContext(SecurityExpressionHandler handler) { FilterInvocation f = new FilterInvocation(getRequest(), getResponse(), new FilterChain() { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { throw new UnsupportedOperationException(); } }); - return ExpressionUtils.evaluateAsBoolean(accessExpression, handler.createEvaluationContext(currentUser, f)); + return handler.createEvaluationContext(SecurityContextHolder.getContext().getAuthentication(), f); } /** diff --git a/taglibs/src/main/java/org/springframework/security/taglibs/authz/JspAuthorizeTag.java b/taglibs/src/main/java/org/springframework/security/taglibs/authz/JspAuthorizeTag.java index d4f5991d80..1e39b9eda8 100644 --- a/taglibs/src/main/java/org/springframework/security/taglibs/authz/JspAuthorizeTag.java +++ b/taglibs/src/main/java/org/springframework/security/taglibs/authz/JspAuthorizeTag.java @@ -1,6 +1,7 @@ package org.springframework.security.taglibs.authz; import java.io.IOException; +import java.util.*; import javax.servlet.ServletContext; import javax.servlet.ServletRequest; @@ -9,7 +10,19 @@ import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; +import org.springframework.expression.BeanResolver; +import org.springframework.expression.ConstructorResolver; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.MethodResolver; +import org.springframework.expression.OperatorOverloader; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.TypeLocator; +import org.springframework.expression.TypedValue; +import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.taglibs.TagLibConfig; +import org.springframework.security.web.FilterInvocation; import org.springframework.web.util.ExpressionEvaluationUtils; /** @@ -60,6 +73,11 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag { } } + @Override + protected EvaluationContext createExpressionEvaluationContext(SecurityExpressionHandler handler) { + return new PageContextVariableLookupEvaluationContext(super.createExpressionEvaluationContext(handler)); + } + /** * Default processing of the end tag returning EVAL_PAGE. * @@ -126,4 +144,62 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag { return pageContext.getServletContext(); } + private final class PageContextVariableLookupEvaluationContext implements EvaluationContext { + + private EvaluationContext delegate; + + private PageContextVariableLookupEvaluationContext(EvaluationContext delegate) { + this.delegate = delegate; + } + + public TypedValue getRootObject() { + return delegate.getRootObject(); + } + + public List getConstructorResolvers() { + return delegate.getConstructorResolvers(); + } + + public List getMethodResolvers() { + return delegate.getMethodResolvers(); + } + + public List getPropertyAccessors() { + return delegate.getPropertyAccessors(); + } + + public TypeLocator getTypeLocator() { + return delegate.getTypeLocator(); + } + + public TypeConverter getTypeConverter() { + return delegate.getTypeConverter(); + } + + public TypeComparator getTypeComparator() { + return delegate.getTypeComparator(); + } + + public OperatorOverloader getOperatorOverloader() { + return delegate.getOperatorOverloader(); + } + + public BeanResolver getBeanResolver() { + return delegate.getBeanResolver(); + } + + public void setVariable(String name, Object value) { + delegate.setVariable(name, value); + } + + public Object lookupVariable(String name) { + Object result = delegate.lookupVariable(name); + + if (result == null) { + result = pageContext.findAttribute(name); + } + return result; + } + } + } diff --git a/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java b/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java index 77455dc9dc..ea2615b3d9 100644 --- a/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java +++ b/taglibs/src/test/java/org/springframework/security/taglibs/authz/AuthorizeTagTests.java @@ -44,6 +44,7 @@ public class AuthorizeTagTests { //~ Instance fields ================================================================================================ private JspAuthorizeTag authorizeTag; + private MockHttpServletRequest request = new MockHttpServletRequest(); private final TestingAuthenticationToken currentUser = new TestingAuthenticationToken("abc", "123", "ROLE SUPERVISOR", "ROLE_TELLER"); //~ Methods ======================================================================================================== @@ -57,7 +58,7 @@ public class AuthorizeTagTests { MockServletContext servletCtx = new MockServletContext(); servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx); authorizeTag = new JspAuthorizeTag(); - authorizeTag.setPageContext(new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse())); + authorizeTag.setPageContext(new MockPageContext(servletCtx, request, new MockHttpServletResponse())); } @After @@ -86,6 +87,13 @@ public class AuthorizeTagTests { assertEquals(Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag()); } + @Test + public void requestAttributeIsResolvedAsElVariable() throws JspException { + request.setAttribute("blah", "blah"); + authorizeTag.setAccess("#blah == 'blah'"); + assertEquals(Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag()); + } + // url attribute tests @Test public void skipsBodyWithUrlSetIfNoAuthenticationPresent() throws Exception { diff --git a/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java b/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java index 360ce5d40a..d42599d809 100644 --- a/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java +++ b/web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java @@ -14,6 +14,8 @@ public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpress @Override protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) { - return new WebSecurityExpressionRoot(authentication, fi); + WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi); + root.setPermissionEvaluator(getPermissionEvaluator()); + return root; } }