Return-Path: Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: (qmail 52733 invoked from network); 4 Nov 2008 21:43:37 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 4 Nov 2008 21:43:37 -0000 Received: (qmail 91836 invoked by uid 500); 4 Nov 2008 21:43:36 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 91782 invoked by uid 500); 4 Nov 2008 21:43:36 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 91770 invoked by uid 99); 4 Nov 2008 21:43:36 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 04 Nov 2008 13:43:36 -0800 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 04 Nov 2008 21:42:27 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 6BE8823888A2; Tue, 4 Nov 2008 13:42:39 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r711422 - /tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java Date: Tue, 04 Nov 2008 21:42:39 -0000 To: dev@tomcat.apache.org From: rjung@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20081104214239.6BE8823888A2@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 * userRoleName property. * + *
  • A default role can be assigned to each user that was successfully + * authenticated by setting the commonRole property to the + * name of this role. The role doesn't have to exist in the directory.
  • + * + *
  • If the directory server contains nested roles, you can search for roles + * recursively by setting roleRecursionLimit to some positive value. + * The default value is 0, so role searches do not recurse.
  • + * *
  • Note that the standard <security-role-ref> 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 recursiveMap, Set 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 groupMap = new HashMap(); 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 keys = groupMap.keySet(); if (containerLog.isTraceEnabled()) { - if (list != null) { - containerLog.trace(" Returning " + list.size() + " roles"); - Iterator 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 i = keys.iterator(); i.hasNext();) { + Object k = i.next(); + containerLog.trace( " Found direct role " + k + " -> " + groupMap.get(k)); } } - return (list); + HashSet recursiveSet = new HashSet(); + HashMap recursiveMap = new HashMap(); + + for (Iterator i = keys.iterator(); i.hasNext();) { + String k = i.next(); + getRolesRecursive(0, context, recursiveMap, recursiveSet, groupMap.get(k), k); + } + + HashSet resultSet = new HashSet(list); + resultSet.addAll(recursiveMap.values()); + + if (containerLog.isTraceEnabled()) { + containerLog.trace(" Returning " + resultSet.size() + " roles"); + for (Iterator i = resultSet.iterator(); i.hasNext();) + containerLog.trace( " Found role " + i.next()); + } + + return new ArrayList(resultSet); } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org