SEC-1749: Add support for PageContext lookup of objects and use of PermissionEvaluator when using web access expressions.
This commit is contained in:
parent
c758f36629
commit
63f160dc72
core/src/main/java/org/springframework/security/access/expression
taglibs/src
main/java/org/springframework/security/taglibs/authz
test/java/org/springframework/security/taglibs/authz
web/src/main/java/org/springframework/security/web/access/expression
|
@ -8,6 +8,7 @@ import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.ExpressionParser;
|
import org.springframework.expression.ExpressionParser;
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
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.hierarchicalroles.RoleHierarchy;
|
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||||
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
||||||
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
||||||
|
@ -25,6 +26,7 @@ public abstract class AbstractSecurityExpressionHandler<T> implements SecurityEx
|
||||||
private final ExpressionParser expressionParser = new SpelExpressionParser();
|
private final ExpressionParser expressionParser = new SpelExpressionParser();
|
||||||
private BeanResolver br;
|
private BeanResolver br;
|
||||||
private RoleHierarchy roleHierarchy;
|
private RoleHierarchy roleHierarchy;
|
||||||
|
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
|
||||||
|
|
||||||
public final ExpressionParser getExpressionParser() {
|
public final ExpressionParser getExpressionParser() {
|
||||||
return expressionParser;
|
return expressionParser;
|
||||||
|
@ -77,6 +79,14 @@ public abstract class AbstractSecurityExpressionHandler<T> implements SecurityEx
|
||||||
this.roleHierarchy = roleHierarchy;
|
this.roleHierarchy = roleHierarchy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected PermissionEvaluator getPermissionEvaluator() {
|
||||||
|
return permissionEvaluator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {
|
||||||
|
this.permissionEvaluator = permissionEvaluator;
|
||||||
|
}
|
||||||
|
|
||||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||||
br = new BeanFactoryResolver(applicationContext);
|
br = new BeanFactoryResolver(applicationContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.springframework.security.access.expression.method;
|
package org.springframework.security.access.expression;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import org.springframework.security.core.Authentication;
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class DenyAllPermissionEvaluator implements PermissionEvaluator {
|
public class DenyAllPermissionEvaluator implements PermissionEvaluator {
|
||||||
|
|
||||||
private final Log logger = LogFactory.getLog(getClass());
|
private final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
|
@ -14,6 +14,7 @@ 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.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.SecurityExpressionRoot;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
@ -31,7 +32,6 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||||
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
|
|
||||||
private PermissionCacheOptimizer permissionCacheOptimizer = null;
|
private PermissionCacheOptimizer permissionCacheOptimizer = null;
|
||||||
|
|
||||||
public DefaultMethodSecurityExpressionHandler() {
|
public DefaultMethodSecurityExpressionHandler() {
|
||||||
|
@ -48,7 +48,7 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
|
||||||
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
|
protected SecurityExpressionRoot 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(permissionEvaluator);
|
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
@ -140,10 +140,6 @@ public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpr
|
||||||
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {
|
|
||||||
this.permissionEvaluator = permissionEvaluator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPermissionCacheOptimizer(PermissionCacheOptimizer permissionCacheOptimizer) {
|
public void setPermissionCacheOptimizer(PermissionCacheOptimizer permissionCacheOptimizer) {
|
||||||
this.permissionCacheOptimizer = permissionCacheOptimizer;
|
this.permissionCacheOptimizer = permissionCacheOptimizer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.aop.framework.AopProxyUtils;
|
import org.springframework.aop.framework.AopProxyUtils;
|
||||||
import org.springframework.aop.support.AopUtils;
|
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.LocalVariableTableParameterNameDiscoverer;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
|
@ -27,7 +25,6 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||||
|
|
||||||
private ParameterNameDiscoverer parameterNameDiscoverer;
|
private ParameterNameDiscoverer parameterNameDiscoverer;
|
||||||
private final MethodInvocation mi;
|
private final MethodInvocation mi;
|
||||||
private ApplicationContext appContext;
|
|
||||||
private boolean argumentsAdded;
|
private boolean argumentsAdded;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,16 +61,6 @@ class MethodSecurityEvaluationContext extends StandardEvaluationContext {
|
||||||
return variable;
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
import org.springframework.expression.ParseException;
|
import org.springframework.expression.ParseException;
|
||||||
import org.springframework.security.access.expression.ExpressionUtils;
|
import org.springframework.security.access.expression.ExpressionUtils;
|
||||||
|
@ -161,8 +162,7 @@ public abstract class AbstractAuthorizeTag {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public boolean authorizeUsingAccessExpression() throws IOException {
|
public boolean authorizeUsingAccessExpression() throws IOException {
|
||||||
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
|
if (SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||||
if (currentUser == null) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,13 +178,20 @@ public abstract class AbstractAuthorizeTag {
|
||||||
throw ioException;
|
throw ioException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ExpressionUtils.evaluateAsBoolean(accessExpression, createExpressionEvaluationContext(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the {@code EvaluationContext} to be customized for variable lookup etc.
|
||||||
|
*/
|
||||||
|
protected EvaluationContext createExpressionEvaluationContext(SecurityExpressionHandler<FilterInvocation> handler) {
|
||||||
FilterInvocation f = new FilterInvocation(getRequest(), getResponse(), new FilterChain() {
|
FilterInvocation f = new FilterInvocation(getRequest(), getResponse(), new FilterChain() {
|
||||||
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
|
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return ExpressionUtils.evaluateAsBoolean(accessExpression, handler.createEvaluationContext(currentUser, f));
|
return handler.createEvaluationContext(SecurityContextHolder.getContext().getAuthentication(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.springframework.security.taglibs.authz;
|
package org.springframework.security.taglibs.authz;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
|
@ -9,7 +10,19 @@ import javax.servlet.jsp.JspException;
|
||||||
import javax.servlet.jsp.PageContext;
|
import javax.servlet.jsp.PageContext;
|
||||||
import javax.servlet.jsp.tagext.Tag;
|
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.taglibs.TagLibConfig;
|
||||||
|
import org.springframework.security.web.FilterInvocation;
|
||||||
import org.springframework.web.util.ExpressionEvaluationUtils;
|
import org.springframework.web.util.ExpressionEvaluationUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,6 +73,11 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected EvaluationContext createExpressionEvaluationContext(SecurityExpressionHandler<FilterInvocation> handler) {
|
||||||
|
return new PageContextVariableLookupEvaluationContext(super.createExpressionEvaluationContext(handler));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default processing of the end tag returning EVAL_PAGE.
|
* Default processing of the end tag returning EVAL_PAGE.
|
||||||
*
|
*
|
||||||
|
@ -126,4 +144,62 @@ public class JspAuthorizeTag extends AbstractAuthorizeTag implements Tag {
|
||||||
return pageContext.getServletContext();
|
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<ConstructorResolver> getConstructorResolvers() {
|
||||||
|
return delegate.getConstructorResolvers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MethodResolver> getMethodResolvers() {
|
||||||
|
return delegate.getMethodResolvers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PropertyAccessor> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class AuthorizeTagTests {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private JspAuthorizeTag authorizeTag;
|
private JspAuthorizeTag authorizeTag;
|
||||||
|
private MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
private final TestingAuthenticationToken currentUser = new TestingAuthenticationToken("abc", "123", "ROLE SUPERVISOR", "ROLE_TELLER");
|
private final TestingAuthenticationToken currentUser = new TestingAuthenticationToken("abc", "123", "ROLE SUPERVISOR", "ROLE_TELLER");
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
@ -57,7 +58,7 @@ public class AuthorizeTagTests {
|
||||||
MockServletContext servletCtx = new MockServletContext();
|
MockServletContext servletCtx = new MockServletContext();
|
||||||
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
|
servletCtx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ctx);
|
||||||
authorizeTag = new JspAuthorizeTag();
|
authorizeTag = new JspAuthorizeTag();
|
||||||
authorizeTag.setPageContext(new MockPageContext(servletCtx, new MockHttpServletRequest(), new MockHttpServletResponse()));
|
authorizeTag.setPageContext(new MockPageContext(servletCtx, request, new MockHttpServletResponse()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -86,6 +87,13 @@ public class AuthorizeTagTests {
|
||||||
assertEquals(Tag.EVAL_BODY_INCLUDE, authorizeTag.doStartTag());
|
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
|
// url attribute tests
|
||||||
@Test
|
@Test
|
||||||
public void skipsBodyWithUrlSetIfNoAuthenticationPresent() throws Exception {
|
public void skipsBodyWithUrlSetIfNoAuthenticationPresent() throws Exception {
|
||||||
|
|
|
@ -14,6 +14,8 @@ public class DefaultWebSecurityExpressionHandler extends AbstractSecurityExpress
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
|
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
|
||||||
return new WebSecurityExpressionRoot(authentication, fi);
|
WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
|
||||||
|
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||||
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue