diff --git a/core/src/main/java/org/springframework/security/taglibs/authz/AuthenticationTag.java b/core/src/main/java/org/springframework/security/taglibs/authz/AuthenticationTag.java index b3e628397e..161b68cda8 100644 --- a/core/src/main/java/org/springframework/security/taglibs/authz/AuthenticationTag.java +++ b/core/src/main/java/org/springframework/security/taglibs/authz/AuthenticationTag.java @@ -20,137 +20,109 @@ import org.springframework.security.Authentication; import org.springframework.security.context.SecurityContext; import org.springframework.security.context.SecurityContextHolder; -import org.springframework.security.userdetails.UserDetails; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.BeansException; +import org.springframework.web.util.TagUtils; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import java.util.HashSet; -import java.util.Set; - import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; - /** * An {@link javax.servlet.jsp.tagext.Tag} implementation that allows convenient access to the current - * Authentication object.

Whilst JSPs can access the SecurityContext directly, this tag - * avoids handling null conditions. The tag also properly accommodates - * Authentication.getPrincipal(), which can either be a String or a - * UserDetails.

+ * Authentication object. The operation attribute + *

+ * Whilst JSPs can access the SecurityContext directly, this tag avoids handling null conditions. * - * @author Ben Alex + * @author Thomas Champagne * @version $Id$ */ public class AuthenticationTag extends TagSupport { - //~ Static fields/initializers ===================================================================================== - - private static final Set methodPrefixValidOptions = new HashSet(); - - static { - methodPrefixValidOptions.add("get"); - methodPrefixValidOptions.add("is"); - } //~ Instance fields ================================================================================================ - private String methodPrefix = "get"; - private String operation = ""; + private String var; + private String property; + private int scope; + private boolean scopeSpecified; + //~ Methods ======================================================================================================== + public AuthenticationTag() { + init(); + } + + // resets local state + private void init() { + var = null; + scopeSpecified = false; + scope = PageContext.PAGE_SCOPE; + } + public void setVar(String var) { + this.var = var; + } + + public void setProperty(String operation) { + this.property = operation; + } + + public void setScope(String scope) { + this.scope = TagUtils.getScope(scope); + this.scopeSpecified = true; + } + public int doStartTag() throws JspException { - if ((null == operation) || "".equals(operation)) { - return Tag.SKIP_BODY; - } - - validateArguments(); - - if ((SecurityContextHolder.getContext() == null) - || !(SecurityContextHolder.getContext() instanceof SecurityContext) - || (((SecurityContext) SecurityContextHolder.getContext()).getAuthentication() == null)) { - return Tag.SKIP_BODY; - } - - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - - if (auth.getPrincipal() == null) { - return Tag.SKIP_BODY; - } else if (auth.getPrincipal() instanceof UserDetails) { - writeMessage(invokeOperation(auth.getPrincipal())); - - return Tag.SKIP_BODY; - } else { - writeMessage(auth.getPrincipal().toString()); - - return Tag.SKIP_BODY; - } + return super.doStartTag(); } - public String getMethodPrefix() { - return methodPrefix; - } + public int doEndTag() throws JspException { + Object result = null; + // determine the value by... + if (property != null) { + if ((SecurityContextHolder.getContext() == null) + || !(SecurityContextHolder.getContext() instanceof SecurityContext) + || (SecurityContextHolder.getContext().getAuthentication() == null)) { + return Tag.EVAL_PAGE; + } - public String getOperation() { - return operation; - } + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - protected String invokeOperation(Object obj) throws JspException { - Class clazz = obj.getClass(); - String methodToInvoke = getOperation(); - StringBuffer methodName = new StringBuffer(); - methodName.append(getMethodPrefix()); - methodName.append(methodToInvoke.substring(0, 1).toUpperCase()); - methodName.append(methodToInvoke.substring(1)); - - Method method = null; - - try { - method = clazz.getMethod(methodName.toString(), (Class[]) null); - } catch (SecurityException se) { - throw new JspException(se); - } catch (NoSuchMethodException nsme) { - throw new JspException(nsme); + if (auth.getPrincipal() == null) { + return Tag.EVAL_PAGE; + } else { + try { + BeanWrapperImpl wrapper = new BeanWrapperImpl(auth); + result = wrapper.getPropertyValue(property); + } catch (BeansException e) { + throw new JspException(e); + } + } } - Object retVal = null; - - try { - retVal = method.invoke(obj, (Object[]) null); - } catch (IllegalArgumentException iae) { - throw new JspException(iae); - } catch (IllegalAccessException iae) { - throw new JspException(iae); - } catch (InvocationTargetException ite) { - throw new JspException(ite); - } - - if (retVal == null) { - retVal = ""; - } - - return retVal.toString(); - } - - public void setMethodPrefix(String methodPrefix) { - this.methodPrefix = methodPrefix; - } - - public void setOperation(String operation) { - this.operation = operation; - } - - protected void validateArguments() throws JspException { - if ((getMethodPrefix() != null) && !getMethodPrefix().equals("")) { - if (!methodPrefixValidOptions.contains(getMethodPrefix())) { - throw new JspException("Authorization tag : no valid method prefix available"); + if (var != null) { + /* + * Store the result, letting an IllegalArgumentException + * propagate back if the scope is invalid (e.g., if an attempt + * is made to store something in the session without any + * HttpSession existing). + */ + if (result != null) { + pageContext.setAttribute(var, result, scope); + } else { + if (scopeSpecified) { + pageContext.removeAttribute(var, scope); + } else { + pageContext.removeAttribute(var); + } } } else { - throw new JspException("Authorization tag : no method prefix available"); + writeMessage(result.toString()); } + return EVAL_PAGE; } protected void writeMessage(String msg) throws JspException { diff --git a/core/src/main/java/org/springframework/security/taglibs/velocity/AuthzImpl.java b/core/src/main/java/org/springframework/security/taglibs/velocity/AuthzImpl.java index 966ba8178a..f02e549806 100644 --- a/core/src/main/java/org/springframework/security/taglibs/velocity/AuthzImpl.java +++ b/core/src/main/java/org/springframework/security/taglibs/velocity/AuthzImpl.java @@ -68,7 +68,7 @@ public class AuthzImpl implements Authz { public String getPrincipal() { MyAuthenticationTag authenticationTag = new MyAuthenticationTag(); - authenticationTag.setOperation("username"); + authenticationTag.setProperty("username"); try { authenticationTag.doStartTag(); diff --git a/core/src/main/resources/org/springframework/security/taglibs/security.tld b/core/src/main/resources/org/springframework/security/taglibs/security.tld index aafd6ee4cd..5aaad516c7 100644 --- a/core/src/main/resources/org/springframework/security/taglibs/security.tld +++ b/core/src/main/resources/org/springframework/security/taglibs/security.tld @@ -8,8 +8,8 @@ security http://www.springframework.org/security/tags - Spring Securitys Authorization Tag Library - $Id: authz.tld 2176 2007-10-03 14:02:39Z luke_t $ + Spring Security Authorization Tag Library + $Id$ @@ -51,35 +51,43 @@ - - authentication - org.springframework.security.taglibs.authz.AuthenticationTag - + + authentication + org.springframework.security.taglibs.authz.AuthenticationTag + Allows access to the current Authentication object. - - - - operation - true - true - - Must be one of the methods of an instance that implements the UserDetails - interface. Use the JavaBean style property, you can provide a custom prefix - for the method to call. - - - - - methodPrefix - false - true - - Must be get or is. This is used to determine the name of the - method to be called. The default is get. - - - + + + property + true + true + + Property of the Authentication object which should be output. Supports nested + properties. For example if the principal object is an instance of UserDetails, + te property "principal.username" will return the username. Alternatively, using + "name" will call getName method on the Authentication object directly. + + + + var + false + false + + Name of the exported scoped variable for the + exception thrown from a nested action. The type of the + scoped variable is the type of the exception thrown. + + + + scope + false + false + + Scope for var. + + + acl diff --git a/core/src/test/java/org/springframework/security/taglibs/authz/AuthenticationTagTests.java b/core/src/test/java/org/springframework/security/taglibs/authz/AuthenticationTagTests.java index 0565fc23e5..6440cec8e5 100644 --- a/core/src/test/java/org/springframework/security/taglibs/authz/AuthenticationTagTests.java +++ b/core/src/test/java/org/springframework/security/taglibs/authz/AuthenticationTagTests.java @@ -19,11 +19,8 @@ import junit.framework.TestCase; import org.springframework.security.Authentication; import org.springframework.security.GrantedAuthority; - import org.springframework.security.context.SecurityContextHolder; - import org.springframework.security.providers.TestingAuthenticationToken; - import org.springframework.security.userdetails.User; import javax.servlet.jsp.JspException; @@ -40,6 +37,8 @@ public class AuthenticationTagTests extends TestCase { //~ Instance fields ================================================================================================ private final MyAuthenticationTag authenticationTag = new MyAuthenticationTag(); + private final Authentication auth = new TestingAuthenticationToken(new User("rodUserDetails", "koala", true, true, true, + true, new GrantedAuthority[] {}), "koala", new GrantedAuthority[] {}); //~ Methods ======================================================================================================== @@ -47,86 +46,67 @@ public class AuthenticationTagTests extends TestCase { SecurityContextHolder.clearContext(); } - public void testOperationAndMethodPrefixWhenPrincipalIsAUserDetailsInstance() - throws JspException { - Authentication auth = new TestingAuthenticationToken(new User("rodUserDetails", "koala", true, true, true, - true, new GrantedAuthority[] {}), "koala", new GrantedAuthority[] {}); + public void testOperationWhenPrincipalIsAUserDetailsInstance()throws JspException { SecurityContextHolder.getContext().setAuthentication(auth); - authenticationTag.setOperation("username"); - authenticationTag.setMethodPrefix("get"); + authenticationTag.setProperty("name"); assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); + assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag()); assertEquals("rodUserDetails", authenticationTag.getLastMessage()); } public void testOperationWhenPrincipalIsAString() throws JspException { - Authentication auth = new TestingAuthenticationToken("rodAsString", "koala", new GrantedAuthority[] {}); - SecurityContextHolder.getContext().setAuthentication(auth); + SecurityContextHolder.getContext().setAuthentication( + new TestingAuthenticationToken("rodAsString", "koala", new GrantedAuthority[] {})); - authenticationTag.setOperation("principal"); + authenticationTag.setProperty("principal"); assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); + assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag()); assertEquals("rodAsString", authenticationTag.getLastMessage()); } - public void testOperationWhenPrincipalIsAUserDetailsInstance() - throws JspException { - Authentication auth = new TestingAuthenticationToken(new User("rodUserDetails", "koala", true, true, true, - true, new GrantedAuthority[] {}), "koala", new GrantedAuthority[] {}); + public void testNestedPropertyIsReadCorrectly() throws JspException { SecurityContextHolder.getContext().setAuthentication(auth); - authenticationTag.setOperation("username"); + authenticationTag.setProperty("principal.username"); assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); + assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag()); assertEquals("rodUserDetails", authenticationTag.getLastMessage()); } public void testOperationWhenPrincipalIsNull() throws JspException { - Authentication auth = new TestingAuthenticationToken(null, "koala", new GrantedAuthority[] {}); - SecurityContextHolder.getContext().setAuthentication(auth); + SecurityContextHolder.getContext().setAuthentication( + new TestingAuthenticationToken(null, "koala", new GrantedAuthority[] {})); - authenticationTag.setOperation("principal"); + authenticationTag.setProperty("principal"); assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); + assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag()); } public void testOperationWhenSecurityContextIsNull() throws Exception { SecurityContextHolder.getContext().setAuthentication(null); - authenticationTag.setOperation("principal"); + authenticationTag.setProperty("principal"); assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); + assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag()); assertEquals(null, authenticationTag.getLastMessage()); } public void testSkipsBodyIfNullOrEmptyOperation() throws Exception { - authenticationTag.setOperation(""); - assertEquals("", authenticationTag.getOperation()); + authenticationTag.setProperty(""); assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); + assertEquals(Tag.EVAL_PAGE, authenticationTag.doEndTag()); } - public void testThrowsExceptionForUnrecognisedMethodPrefix() { - Authentication auth = new TestingAuthenticationToken(new User("rodUserDetails", "koala", true, true, true, - true, new GrantedAuthority[] {}), "koala", new GrantedAuthority[] {}); + public void testThrowsExceptionForUnrecognisedProperty() { SecurityContextHolder.getContext().setAuthentication(auth); - authenticationTag.setOperation("username"); - authenticationTag.setMethodPrefix("qrq"); - - try { - authenticationTag.doStartTag(); - fail("Should have thrown a JspException"); - } catch (JspException expected) { - assertTrue(true); - } - } - - public void testThrowsExceptionForUnrecognisedOperation() { - Authentication auth = new TestingAuthenticationToken(new User("rodUserDetails", "koala", true, true, true, - true, new GrantedAuthority[] {}), "koala", new GrantedAuthority[] {}); - SecurityContextHolder.getContext().setAuthentication(auth); - authenticationTag.setOperation("qsq"); + authenticationTag.setProperty("qsq"); try { authenticationTag.doStartTag(); + authenticationTag.doEndTag(); fail("Should have throwns JspException"); } catch (JspException expected) { - assertTrue(true); } } diff --git a/samples/tutorial/src/main/webapp/index.jsp b/samples/tutorial/src/main/webapp/index.jsp index 3e382a6bf2..edf1d00d0b 100644 --- a/samples/tutorial/src/main/webapp/index.jsp +++ b/samples/tutorial/src/main/webapp/index.jsp @@ -1,14 +1,18 @@ +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

Home Page

-Anyone can view this page.

- -If you're logged in, you can list accounts.

- - -Your principal object is....: <%= request.getUserPrincipal() %>

+

+Anyone can view this page. +

+

+If you're logged in, you can list accounts. +

+

+Your principal object is....: <%= request.getUserPrincipal() %> +

-

Secure page -

Extremely secure page +

Secure page

+

Extremely secure page

\ No newline at end of file diff --git a/samples/tutorial/src/main/webapp/secure/index.jsp b/samples/tutorial/src/main/webapp/secure/index.jsp index b774c40ed8..e44be8bcd7 100644 --- a/samples/tutorial/src/main/webapp/secure/index.jsp +++ b/samples/tutorial/src/main/webapp/secure/index.jsp @@ -1,13 +1,34 @@ +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> +

Secure Page

+

This is a protected page. You can get to me if you've been remembered, -or if you've authenticated this session.

- -<%if (request.isUserInRole("ROLE_SUPERVISOR")) { %> - You are a supervisor! You can therefore see the extremely secure page.

-<% } %> - +or if you've authenticated this session. +

+ + + You are a supervisor! You can therefore see the extremely secure page.

+
+ +

Properties obtained using <sec:authentication /> tag

+ + + + + + + + + + + + + + +
TagValue
<sec:authentication property='name' />
<sec:authentication property='principal.username' />
<sec:authentication property='principal.enabled' />
<sec:authentication property='principal.accountNonLocked' />
+

Home

Logout