diff --git a/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java b/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java
index 706181bfc0..2e37bf7c07 100644
--- a/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java
+++ b/core/src/main/java/org/acegisecurity/taglibs/authz/AuthenticationTag.java
@@ -17,10 +17,17 @@ package net.sf.acegisecurity.taglibs.authz;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.UserDetails;
+import net.sf.acegisecurity.context.SecurityContext;
import net.sf.acegisecurity.context.SecurityContextHolder;
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.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
@@ -43,14 +50,28 @@ import javax.servlet.jsp.tagext.TagSupport;
public class AuthenticationTag extends TagSupport {
//~ Static fields/initializers =============================================
- public static final String OPERATION_PRINCIPAL = "principal";
+ private final static Set methodPrefixValidOptions = new HashSet();
+
+ static {
+ methodPrefixValidOptions.add("get");
+ methodPrefixValidOptions.add("is");
+ }
//~ Instance fields ========================================================
+ private String methodPrefix = "get";
private String operation = "";
//~ Methods ================================================================
+ public void setMethodPrefix(String methodPrefix) {
+ this.methodPrefix = methodPrefix;
+ }
+
+ public String getMethodPrefix() {
+ return methodPrefix;
+ }
+
public void setOperation(String operation) {
this.operation = operation;
}
@@ -64,11 +85,12 @@ public class AuthenticationTag extends TagSupport {
return Tag.SKIP_BODY;
}
- if (!OPERATION_PRINCIPAL.equalsIgnoreCase(operation)) {
- throw new JspException("Unsupported use of auth:authentication tag");
- }
+ validateArguments();
- if (SecurityContextHolder.getContext().getAuthentication() == null) {
+ if ((SecurityContextHolder.getContext() == null)
+ || !(SecurityContextHolder.getContext() instanceof SecurityContext)
+ || (((SecurityContext) SecurityContextHolder.getContext())
+ .getAuthentication() == null)) {
return Tag.SKIP_BODY;
}
@@ -78,7 +100,7 @@ public class AuthenticationTag extends TagSupport {
if (auth.getPrincipal() == null) {
return Tag.SKIP_BODY;
} else if (auth.getPrincipal() instanceof UserDetails) {
- writeMessage(((UserDetails) auth.getPrincipal()).getUsername());
+ writeMessage(invokeOperation(auth.getPrincipal()));
return Tag.SKIP_BODY;
} else {
@@ -88,6 +110,55 @@ public class AuthenticationTag extends TagSupport {
}
}
+ 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.getDeclaredMethod(methodName.toString(), null);
+ } catch (SecurityException se) {
+ throw new JspException(se);
+ } catch (NoSuchMethodException nsme) {
+ throw new JspException(nsme);
+ }
+
+ Object retVal = null;
+
+ try {
+ retVal = method.invoke(obj, 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();
+ }
+
+ protected void validateArguments() throws JspException {
+ if ((getMethodPrefix() != null) && !getMethodPrefix().equals("")) {
+ if (!methodPrefixValidOptions.contains(getMethodPrefix())) {
+ throw new JspException(
+ "Authorization tag : no valid method prefix available");
+ }
+ } else {
+ throw new JspException(
+ "Authorization tag : no method prefix available");
+ }
+ }
+
protected void writeMessage(String msg) throws JspException {
try {
pageContext.getOut().write(String.valueOf(msg));
diff --git a/core/src/main/resources/org/acegisecurity/taglibs/authz.tld b/core/src/main/resources/org/acegisecurity/taglibs/authz.tld
index e46f254b16..4b298cec4b 100644
--- a/core/src/main/resources/org/acegisecurity/taglibs/authz.tld
+++ b/core/src/main/resources/org/acegisecurity/taglibs/authz.tld
@@ -63,10 +63,21 @@
true
true
- Must be "principal", for a String representation of the
- username. An attribute to aid in future extension of the tag.
+ 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.
+
+
diff --git a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java
index 0f963fdeba..646a4b17bf 100644
--- a/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java
+++ b/core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java
@@ -40,6 +40,20 @@ public class AuthenticationTagTests extends TestCase {
//~ Methods ================================================================
+ public void testOperationAndMethodPrefixWhenPrincipalIsAUserDetailsInstance()
+ throws JspException {
+ Authentication auth = new TestingAuthenticationToken(new User(
+ "marissaUserDetails", "koala", true, true, true, true,
+ new GrantedAuthority[] {}), "koala",
+ new GrantedAuthority[] {});
+ SecurityContextHolder.getContext().setAuthentication(auth);
+
+ authenticationTag.setOperation("username");
+ authenticationTag.setMethodPrefix("get");
+ assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
+ assertEquals("marissaUserDetails", authenticationTag.getLastMessage());
+ }
+
public void testOperationWhenPrincipalIsAString() throws JspException {
Authentication auth = new TestingAuthenticationToken("marissaAsString",
"koala", new GrantedAuthority[] {});
@@ -58,7 +72,7 @@ public class AuthenticationTagTests extends TestCase {
new GrantedAuthority[] {});
SecurityContextHolder.getContext().setAuthentication(auth);
- authenticationTag.setOperation("principal");
+ authenticationTag.setOperation("username");
assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
assertEquals("marissaUserDetails", authenticationTag.getLastMessage());
}
@@ -89,7 +103,29 @@ public class AuthenticationTagTests extends TestCase {
assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
}
+ public void testThrowsExceptionForUnrecognisedMethodPrefix() {
+ Authentication auth = new TestingAuthenticationToken(new User(
+ "marissaUserDetails", "koala", true, true, true, true,
+ new GrantedAuthority[] {}), "koala",
+ new GrantedAuthority[] {});
+ 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(
+ "marissaUserDetails", "koala", true, true, true, true,
+ new GrantedAuthority[] {}), "koala",
+ new GrantedAuthority[] {});
+ SecurityContextHolder.getContext().setAuthentication(auth);
authenticationTag.setOperation("qsq");
try {