You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by rj...@apache.org on 2008/11/04 22:42:39 UTC

svn commit: r711422 - /tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java

Author: rjung
Date: Tue Nov  4 13:42:38 2008
New Revision: 711422

URL: http://svn.apache.org/viewvc?rev=711422&view=rev
Log:
Add ability to recursively search for roles
to JNDIRealm. That way nested groups work.

Modified:
    tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java

Modified: tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java?rev=711422&r1=711421&r2=711422&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java Tue Nov  4 13:42:38 2008
@@ -22,9 +22,13 @@
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import javax.naming.Context;
 import javax.naming.CommunicationException;
@@ -134,6 +138,14 @@
  * in the user's element whose name is configured by the
  * <code>userRoleName</code> property.</li>
  *
+ * <li>A default role can be assigned to each user that was successfully
+ * authenticated by setting the <code>commonRole</code> property to the
+ * name of this role. The role doesn't have to exist in the directory.</li>
+ *
+ * <li>If the directory server contains nested roles, you can search for roles
+ * recursively by setting <code>roleRecursionLimit</code> to some positive value.
+ * The default value is <code>0</code>, so role searches do not recurse.</li>
+ *
  * <li>Note that the standard <code>&lt;security-role-ref&gt;</code> element in
  *     the web application deployment descriptor allows applications to refer
  *     to roles programmatically by names other than those used in the
@@ -307,6 +319,13 @@
 
 
     /**
+     * The maximum recursion depth when resolving roles recursively.
+     * By default we don't resolve roles recursively.
+     */
+    protected int roleRecursionLimit = 0;
+
+
+    /**
      * The base element for role searches.
      */
     protected String roleBase = "";
@@ -638,6 +657,28 @@
 
 
     /**
+     * Return the maximum recursion depth for role searches.
+     */
+    public int getRoleRecursionLimit() {
+
+        return (this.roleRecursionLimit);
+
+    }
+
+
+    /**
+     * Set the maximum recursion depth for role searches.
+     *
+     * @param roleRecursionLimit The new recursion limit
+     */
+    public void setRoleRecursionLimit(int roleRecursionLimit) {
+
+        this.roleRecursionLimit = roleRecursionLimit;
+
+    }
+
+
+    /**
      * Return the base element for role searches.
      */
     public String getRoleBase() {
@@ -1405,6 +1446,69 @@
 
 
     /**
+     * Add roles to a user and search for other roles containing them themselves.
+     * We search recursively with a limited depth.
+     * By default the depth is 0, and we only use direct roles.
+     * The search needs to use the distinguished role names,
+     * but to return the role names.
+     *
+     * @param depth Recursion depth, starting at zero
+     * @param context The directory context we are searching
+     * @param recursiveMap The cumulative result map of role names and DNs.
+     * @param recursiveSet The cumulative result set of role names.
+     * @param groupName The role name to add to the list.
+     * @param groupDName The distinguished name of the role.
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    private void getRolesRecursive(int depth, DirContext context, Map<String, String> recursiveMap, Set<String> recursiveSet,
+                                     String groupName, String groupDName) throws NamingException {
+        if (containerLog.isTraceEnabled())
+            containerLog.trace("Recursive search depth " + depth + " for group '" + groupDName + " (" + groupName + ")'");
+        // Adding the given group to the result set if not already found
+        if (!recursiveSet.contains(groupDName)) {
+            recursiveSet.add(groupDName);
+            recursiveMap.put(groupDName, groupName);
+            if (depth >= roleRecursionLimit) {
+                if (roleRecursionLimit > 0)
+                    containerLog.warn("Terminating recursive role search because of recursion limit " +
+                                      roleRecursionLimit + ", results might be incomplete");
+                return;
+            }
+            // Prepare the parameters for searching groups
+            String filter = roleFormat.format(new String[] { groupDName });
+            SearchControls controls = new SearchControls();
+            controls.setSearchScope(roleSubtree ? SearchControls.SUBTREE_SCOPE : SearchControls.ONELEVEL_SCOPE);
+            controls.setReturningAttributes(new String[] { roleName });
+            if (containerLog.isTraceEnabled()) {
+                containerLog.trace("Recursive search in role base '" + roleBase + "' for attribute '" + roleName + "'" +
+                                   " with filter expression '" + filter + "'");
+            }
+            // Searching groups that assign the given group
+            NamingEnumeration results = context.search(roleBase, filter, controls);
+            if (results != null) {
+                // Iterate over the resulting groups
+                try {
+                    while (results.hasMore()) {
+                        SearchResult result = (SearchResult) results.next();
+                        Attributes attrs = result.getAttributes();
+                        if (attrs == null)
+                            continue;
+                        String dname = getDistinguishedName(context, roleBase, result);
+                        String name = getAttributeValue(roleName, attrs);
+                        if (name != null && dname != null) {
+                           getRolesRecursive(depth+1, context, recursiveMap, recursiveSet, name, dname);
+                        }
+                    }
+                } catch (PartialResultException ex) {
+                    if (!adCompat)
+                        throw ex;
+                }
+            }
+        }
+    }
+
+    /**
      * Return a List of roles associated with the given User.  Any
      * roles present in the user's directory entry are supplemented by
      * a directory search. If no roles are associated with this user,
@@ -1466,33 +1570,52 @@
             context.search(roleBase, filter, controls);
         if (results == null)
             return (list);  // Should never happen, but just in case ...
+
+        HashMap<String, String> groupMap = new HashMap<String, String>();
         try {
             while (results.hasMore()) {
                 SearchResult result = (SearchResult) results.next();
                 Attributes attrs = result.getAttributes();
                 if (attrs == null)
                     continue;
-                list = addAttributeValues(roleName, attrs, list);
+                String dname = getDistinguishedName(context, roleBase, result);
+                String name = getAttributeValue(roleName, attrs);
+                if (name != null && dname != null) {
+                    groupMap.put(dname, name);
+                }
             }
         } catch (PartialResultException ex) {
             if (!adCompat)
                 throw ex;
         }
 
-
+        Set<String> keys = groupMap.keySet();
         if (containerLog.isTraceEnabled()) {
-            if (list != null) {
-                containerLog.trace("  Returning " + list.size() + " roles");
-                Iterator<String> it = list.iterator();
-                while (it.hasNext()) {
-                    containerLog.trace(  "  Found role " + it.next());
-                }
-            } else {
-                containerLog.trace("  getRoles about to return null ");
+            containerLog.trace("  Found " + keys.size() + " direct roles");
+            for (Iterator<String> i = keys.iterator(); i.hasNext();) {
+                Object k = i.next();
+                containerLog.trace(  "  Found direct role " + k + " -> " + groupMap.get(k));
             }
         }
 
-        return (list);
+        HashSet<String> recursiveSet = new HashSet<String>();
+        HashMap<String, String> recursiveMap = new HashMap<String, String>();
+
+        for (Iterator<String> i = keys.iterator(); i.hasNext();) {
+            String k = i.next();
+            getRolesRecursive(0, context, recursiveMap, recursiveSet, groupMap.get(k), k);
+        }
+
+        HashSet<String> resultSet = new HashSet<String>(list);
+        resultSet.addAll(recursiveMap.values());
+
+        if (containerLog.isTraceEnabled()) {
+            containerLog.trace("  Returning " + resultSet.size() + " roles");
+            for (Iterator<String> i = resultSet.iterator(); i.hasNext();)
+                containerLog.trace(  "  Found role " + i.next());
+        }
+
+        return new ArrayList<String>(resultSet);
     }
 
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org