From b3b5cf2c6f5262001075b6b6faeb828d12b01a68 Mon Sep 17 00:00:00 2001 From: Scott Andrews Date: Wed, 5 Mar 2008 19:27:47 +0000 Subject: [PATCH] SWF-485 Introduce a "currentUser" EL variable that resolves to the principal in the security context. --- .../el/SpringSecurityELResolver.java | 68 +++++++++++++++++++ .../el/WebFlowELExpressionParser.java | 5 ++ .../webflow/mvc/MvcViewFactoryCreator.java | 7 ++ 3 files changed, 80 insertions(+) create mode 100644 spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringSecurityELResolver.java diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringSecurityELResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringSecurityELResolver.java new file mode 100644 index 00000000..ea931c3c --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/SpringSecurityELResolver.java @@ -0,0 +1,68 @@ +package org.springframework.webflow.expression.el; + +import java.util.Iterator; + +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.PropertyNotWritableException; + +import org.springframework.security.Authentication; +import org.springframework.security.context.SecurityContextHolder; + +/** + * Custom EL resolver that resolves to the Spring Security Principal object for binding expressions prefixed with + * {@link #SECURITY_PRINCIPAL_VARIABLE_NAME}. For instance "#{currentUser}". + * + * @author Scott Andrews + */ +public class SpringSecurityELResolver extends ELResolver { + + /** + * Name of the security principal variable. + */ + public static final String SECURITY_PRINCIPAL_VARIABLE_NAME = "currentUser"; + + public Class getCommonPropertyType(ELContext elContext, Object base) { + return Object.class; + } + + public Iterator getFeatureDescriptors(ELContext elContext, Object base) { + return null; + } + + public Class getType(ELContext elContext, Object base, Object property) { + if (base == null && SECURITY_PRINCIPAL_VARIABLE_NAME.equals(property)) { + elContext.setPropertyResolved(true); + return Authentication.class; + } else { + return null; + } + } + + public Object getValue(ELContext elContext, Object base, Object property) { + if (base == null && SECURITY_PRINCIPAL_VARIABLE_NAME.equals(property)) { + elContext.setPropertyResolved(true); + return SecurityContextHolder.getContext().getAuthentication(); + } else { + return null; + } + } + + public boolean isReadOnly(ELContext elContext, Object base, Object property) { + if (base == null && SECURITY_PRINCIPAL_VARIABLE_NAME.equals(property)) { + elContext.setPropertyResolved(true); + return true; + } else { + return false; + } + } + + public void setValue(ELContext elContext, Object base, Object property, Object value) { + if (base == null && SECURITY_PRINCIPAL_VARIABLE_NAME.equals(property)) { + elContext.setPropertyResolved(true); + throw new PropertyNotWritableException("The " + SECURITY_PRINCIPAL_VARIABLE_NAME + + " cannot be set with an expression."); + } + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java index aa6fdda1..b7e3dfc8 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/el/WebFlowELExpressionParser.java @@ -14,6 +14,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.binding.expression.el.DefaultELResolver; import org.springframework.binding.expression.el.ELContextFactory; import org.springframework.binding.expression.el.ELExpressionParser; +import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.webflow.core.collection.MutableAttributeMap; import org.springframework.webflow.execution.RequestContext; @@ -23,6 +24,7 @@ import org.springframework.webflow.execution.RequestContext; * FlowDefinition. * * @author Jeremy Grelle + * @author Scott Andrews */ public class WebFlowELExpressionParser extends ELExpressionParser { @@ -59,6 +61,9 @@ public class WebFlowELExpressionParser extends ELExpressionParser { public ELContext getELContext(Object target) { List customResolvers = new ArrayList(); customResolvers.add(new RequestContextELResolver()); + if (ClassUtils.isPresent("org.springframework.security.context.SecurityContextHolder")) { + customResolvers.add(new SpringSecurityELResolver()); + } customResolvers.add(new ImplicitFlowVariableELResolver()); customResolvers.add(new SpringBeanWebFlowELResolver()); customResolvers.add(new ActionMethodELResolver()); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java index 6c4a1770..57669c58 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/MvcViewFactoryCreator.java @@ -14,6 +14,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.io.ContextResource; import org.springframework.core.io.ResourceLoader; +import org.springframework.security.context.SecurityContextHolder; import org.springframework.util.ClassUtils; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.InternalResourceView; @@ -37,10 +38,13 @@ import org.springframework.webflow.execution.ViewFactory; * infrastructure is configured, JSP resources relative to the flow definition being built. * * @author Keith Donald + * @author Scott Andrews */ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationContextAware { private static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.fmt.LocalizationContext"); + private static final boolean springSecurityPresent = ClassUtils + .isPresent("org.springframework.security.context.SecurityContextHolder"); private List viewResolvers; @@ -183,6 +187,9 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon .union(context.getRequestScope()).asMap()); model.put("flowExecutionRequestContext", context); model.put("flowExecutionUrl", context.getFlowExecutionUrl()); + if (springSecurityPresent && !model.containsKey("currentUser")) { + model.put("currentUser", SecurityContextHolder.getContext().getAuthentication()); + } try { view.render(model, (HttpServletRequest) context.getExternalContext().getNativeRequest(), (HttpServletResponse) context.getExternalContext().getNativeResponse());