SEC-67: Enhance taglib to allow retrieval of custom UserDetails methods.

This commit is contained in:
Ben Alex 2005-11-03 13:51:55 +00:00
parent 31a1f0be1a
commit 9be82a3d8f
3 changed files with 127 additions and 9 deletions

View File

@ -17,10 +17,17 @@ package net.sf.acegisecurity.taglibs.authz;
import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.UserDetails; import net.sf.acegisecurity.UserDetails;
import net.sf.acegisecurity.context.SecurityContext;
import net.sf.acegisecurity.context.SecurityContextHolder; import net.sf.acegisecurity.context.SecurityContextHolder;
import java.io.IOException; 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.JspException;
import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport; import javax.servlet.jsp.tagext.TagSupport;
@ -43,14 +50,28 @@ import javax.servlet.jsp.tagext.TagSupport;
public class AuthenticationTag extends TagSupport { public class AuthenticationTag extends TagSupport {
//~ Static fields/initializers ============================================= //~ 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 ======================================================== //~ Instance fields ========================================================
private String methodPrefix = "get";
private String operation = ""; private String operation = "";
//~ Methods ================================================================ //~ Methods ================================================================
public void setMethodPrefix(String methodPrefix) {
this.methodPrefix = methodPrefix;
}
public String getMethodPrefix() {
return methodPrefix;
}
public void setOperation(String operation) { public void setOperation(String operation) {
this.operation = operation; this.operation = operation;
} }
@ -64,11 +85,12 @@ public class AuthenticationTag extends TagSupport {
return Tag.SKIP_BODY; return Tag.SKIP_BODY;
} }
if (!OPERATION_PRINCIPAL.equalsIgnoreCase(operation)) { validateArguments();
throw new JspException("Unsupported use of auth:authentication tag");
}
if (SecurityContextHolder.getContext().getAuthentication() == null) { if ((SecurityContextHolder.getContext() == null)
|| !(SecurityContextHolder.getContext() instanceof SecurityContext)
|| (((SecurityContext) SecurityContextHolder.getContext())
.getAuthentication() == null)) {
return Tag.SKIP_BODY; return Tag.SKIP_BODY;
} }
@ -78,7 +100,7 @@ public class AuthenticationTag extends TagSupport {
if (auth.getPrincipal() == null) { if (auth.getPrincipal() == null) {
return Tag.SKIP_BODY; return Tag.SKIP_BODY;
} else if (auth.getPrincipal() instanceof UserDetails) { } else if (auth.getPrincipal() instanceof UserDetails) {
writeMessage(((UserDetails) auth.getPrincipal()).getUsername()); writeMessage(invokeOperation(auth.getPrincipal()));
return Tag.SKIP_BODY; return Tag.SKIP_BODY;
} else { } 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 { protected void writeMessage(String msg) throws JspException {
try { try {
pageContext.getOut().write(String.valueOf(msg)); pageContext.getOut().write(String.valueOf(msg));

View File

@ -63,8 +63,19 @@
<required>true</required> <required>true</required>
<rtexprvalue>true</rtexprvalue> <rtexprvalue>true</rtexprvalue>
<description> <description>
Must be "principal", for a String representation of the Must be one of the methods of an instance that implements the UserDetails
username. An attribute to aid in future extension of the tag. interface. Use the JavaBean style property, you can provide a custom prefix
for the method to call.
</description>
</attribute>
<attribute>
<name>methodPrefix</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<description>
Must be get or is. This is used to determine the name of the
method to be called. The default is get.
</description> </description>
</attribute> </attribute>
</tag> </tag>

View File

@ -40,6 +40,20 @@ public class AuthenticationTagTests extends TestCase {
//~ Methods ================================================================ //~ 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 { public void testOperationWhenPrincipalIsAString() throws JspException {
Authentication auth = new TestingAuthenticationToken("marissaAsString", Authentication auth = new TestingAuthenticationToken("marissaAsString",
"koala", new GrantedAuthority[] {}); "koala", new GrantedAuthority[] {});
@ -58,7 +72,7 @@ public class AuthenticationTagTests extends TestCase {
new GrantedAuthority[] {}); new GrantedAuthority[] {});
SecurityContextHolder.getContext().setAuthentication(auth); SecurityContextHolder.getContext().setAuthentication(auth);
authenticationTag.setOperation("principal"); authenticationTag.setOperation("username");
assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag());
assertEquals("marissaUserDetails", authenticationTag.getLastMessage()); assertEquals("marissaUserDetails", authenticationTag.getLastMessage());
} }
@ -89,7 +103,29 @@ public class AuthenticationTagTests extends TestCase {
assertEquals(Tag.SKIP_BODY, authenticationTag.doStartTag()); 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() { 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"); authenticationTag.setOperation("qsq");
try { try {