Selaa lähdekoodia

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

Ben Alex 20 vuotta sitten
vanhempi
commit
9be82a3d8f

+ 77 - 6
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.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)) {
-            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;
             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));

+ 13 - 2
core/src/main/resources/org/acegisecurity/taglibs/authz.tld

@@ -63,10 +63,21 @@
 			<required>true</required>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 			<rtexprvalue>true</rtexprvalue>
 			<description>
 			<description>
-                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.
 			</description>
 			</description>
 		</attribute>
 		</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>
+		</attribute>		
 	</tag>
 	</tag>
 
 
 
 

+ 37 - 1
core/src/test/java/org/acegisecurity/taglibs/authz/AuthenticationTagTests.java

@@ -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 {