You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by sebb <se...@gmail.com> on 2009/09/07 14:52:45 UTC

Re: svn commit: r812115 - in /tomcat/tc6.0.x/trunk: STATUS.txt java/org/apache/catalina/realm/JNDIRealm.java webapps/docs/changelog.xml

On 07/09/2009, markt@apache.org <ma...@apache.org> wrote:
> Author: markt
>  Date: Mon Sep  7 12:45:58 2009
>  New Revision: 812115
>
>  URL: http://svn.apache.org/viewvc?rev=812115&view=rev
>  Log:
>  Apply AD improvements
>
>  Modified:
>     tomcat/tc6.0.x/trunk/STATUS.txt
>     tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java
>     tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
>
>  Modified: tomcat/tc6.0.x/trunk/STATUS.txt
>  URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=812115&r1=812114&r2=812115&view=diff
>  ==============================================================================
>  --- tomcat/tc6.0.x/trunk/STATUS.txt (original)
>  +++ tomcat/tc6.0.x/trunk/STATUS.txt Mon Sep  7 12:45:58 2009
>  @@ -144,17 +144,6 @@
>    +1: kkolinko, markt, rjung, funkman
>    -1:
>
>  -* Port Active Directory improvements to JNDIREalm from trunk
>  -  Patch testing successfully by willing volunteer on the users list
>  -  http://people.apache.org/~markt/patches/2009-08-06-ADforJNDIRealm.patch
>  -  +1: markt, kkolinko, funkman
>  -  -1:
>  -  kkolinko: (
>  -     There are several (two) places with a loop printing containerLog.debug(
>  -     "Found role: " + it.next()); It would be better to prepare the whole string
>  -     of roles and print it at once.
>  -  )
>  -
>   * Port TLD processing improvements from trunk
>    There have been quite a few changes to TLD processing and they are tightly
>    coupled. Therefore, this proposal is a series of patches and the patches
>
>  Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java
>  URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java?rev=812115&r1=812114&r2=812115&view=diff
>  ==============================================================================
>  --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java (original)
>  +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/realm/JNDIRealm.java Mon Sep  7 12:45:58 2009
>  @@ -5,9 +5,9 @@
>   * The ASF licenses this file to You under the Apache License, Version 2.0
>   * (the "License"); you may not use this file except in compliance with
>   * the License.  You may obtain a copy of the License at
>  - *
>  + *
>   *      http://www.apache.org/licenses/LICENSE-2.0
>  - *
>  + *
>   * Unless required by applicable law or agreed to in writing, software
>   * distributed under the License is distributed on an "AS IS" BASIS,
>   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>  @@ -24,8 +24,12 @@
>   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.Set;
>
>   import javax.naming.Context;
>   import javax.naming.CommunicationException;
>  @@ -37,6 +41,7 @@
>   import javax.naming.NameParser;
>   import javax.naming.Name;
>   import javax.naming.AuthenticationException;
>  +import javax.naming.PartialResultException;
>   import javax.naming.ServiceUnavailableException;
>   import javax.naming.directory.Attribute;
>   import javax.naming.directory.Attributes;
>  @@ -134,6 +139,15 @@
>   * 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 them
>  + * by setting <code>roleNested</code> to <code>true</code>.
>  + * The default value is <code>false</code>, so role searches will not find
>  + * nested roles.</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
>  @@ -197,14 +211,14 @@
>       */
>      protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
>
>  -
>  +
>      /**
>       * How aliases should be dereferenced during search operations.
>       */
>      protected String derefAliases = null;
>
>      /**
>  -     * Constant that holds the name of the environment property for specifying
>  +     * Constant that holds the name of the environment property for specifying
>       * the manner in which aliases should be dereferenced.
>       */
>      public final static String DEREF_ALIASES = "java.naming.ldap.derefAliases";
>  @@ -230,9 +244,20 @@
>
>
>      /**
>  -     * How should we handle referrals?  Microsoft Active Directory can't handle
>  -     * the default case, so an application authenticating against AD must
>  -     * set referrals to "follow".
>  +     * Should we ignore PartialResultExceptions when iterating over NamingEnumerations?
>  +     * Microsoft Active Directory often returns referrals, which lead
>  +     * to PartialResultExceptions. Unfortunately there's no stable way to detect,
>  +     * if the Exceptions really come from an AD referral.
>  +     * Set to true to ignore PartialResultExceptions.
>  +     */
>  +    protected boolean adCompat = false;
>  +

Why is this protected rather than private?
There are public getters and setters.
Exposing the variable (even if restricted to subclasses) increases the
binding between classes, and makes it harder later should it become
necessary to synch. it.

Same applies to many of the other protected variables.

>  +
>  +    /**
>  +     * How should we handle referrals?  Microsoft Active Directory often returns
>  +     * referrals. If you need to follow them set referrals to "follow".
>  +     * Caution: if your DNS is not part of AD, the LDAP client lib might try
>  +     * to resolve your domain name in DNS to find another LDAP server.
>       */
>      protected String referrals = null;
>
>  @@ -294,7 +319,6 @@
>       */
>      protected MessageFormat[] userPatternFormatArray = null;
>
>  -
>      /**
>       * The base element for role searches.
>       */
>  @@ -332,6 +356,12 @@
>       * Should we search the entire subtree for matching memberships?
>       */
>      protected boolean roleSubtree = false;
>  +
>  +    /**
>  +     * Should we look for nested group in order to determine roles?
>  +     */
>  +    protected boolean roleNested = false;
>  +
>
>      /**
>       * An alternate URL, to which, we should connect if connectionURL fails.
>  @@ -345,9 +375,10 @@
>      protected int connectionAttempt = 0;
>
>      /**
>  -     * The current user pattern to be used for lookup and binding of a user.
>  +     *  Add this role to every authenticated user
>       */
>  -    protected int curUserPattern = 0;
>  +    protected String commonRole = null;
>  +
>
>      // ------------------------------------------------------------- Properties
>
>  @@ -463,11 +494,11 @@
>       */
>      public java.lang.String getDerefAliases() {
>          return derefAliases;
>  -    }
>  -
>  +    }
>  +
>      /**
>       * Set the value for derefAliases to be used when searching the directory.
>  -     *
>  +     *
>       * @param derefAliases New value of property derefAliases.
>       */
>      public void setDerefAliases(java.lang.String derefAliases) {
>  @@ -496,6 +527,23 @@
>
>
>      /**
>  +     * Returns the current settings for handling PartialResultExceptions
>  +     */
>  +    public boolean getAdCompat () {
>  +        return adCompat;
>  +    }
>  +
>  +
>  +    /**
>  +     * How do we handle PartialResultExceptions?
>  +     * True: ignore all PartialResultExceptions.
>  +     */
>  +    public void setAdCompat (boolean adCompat) {
>  +        this.adCompat = adCompat;
>  +    }
>  +
>  +
>  +    /**
>       * Returns the current settings for handling JNDI referrals.
>       */
>      public String getReferrals () {
>  @@ -693,6 +741,28 @@
>          this.roleSubtree = roleSubtree;
>
>      }
>  +
>  +    /**
>  +     * Return the "The nested group search flag" flag.
>  +     */
>  +    public boolean getRoleNested() {
>  +
>  +        return (this.roleNested);
>  +
>  +    }
>  +
>  +
>  +    /**
>  +     * Set the "search subtree for roles" flag.
>  +     *
>  +     * @param roleNested The nested group search flag
>  +     */
>  +    public void setRoleNested(boolean roleNested) {
>  +
>  +        this.roleNested = roleNested;
>  +
>  +    }
>  +
>
>
>      /**
>  @@ -778,6 +848,28 @@
>      }
>
>
>  +    /**
>  +     * Return the common role
>  +     */
>  +    public String getCommonRole() {
>  +
>  +        return commonRole;
>  +
>  +    }
>  +
>  +
>  +    /**
>  +     * Set the common role
>  +     *
>  +     * @param commonRole The common role
>  +     */
>  +    public void setCommonRole(String commonRole) {
>  +
>  +        this.commonRole = commonRole;
>  +
>  +    }
>  +
>  +
>      // ---------------------------------------------------------- Realm Methods
>
>
>  @@ -877,6 +969,8 @@
>                  close(context);
>
>              // Return "not authenticated" for this request
>  +            if (containerLog.isDebugEnabled())
>  +                containerLog.debug("Returning null principal.");
>              return (null);
>
>          }
>  @@ -907,21 +1001,30 @@
>          throws NamingException {
>
>          if (username == null || username.equals("")
>  -            || credentials == null || credentials.equals(""))
>  +            || credentials == null || credentials.equals("")) {
>  +            if (containerLog.isDebugEnabled())
>  +                containerLog.debug("username null or empty: returning null principal.");
>              return (null);
>  +        }
>
>          if (userPatternArray != null) {
>  -            for (curUserPattern = 0;
>  +            for (int curUserPattern = 0;
>                   curUserPattern < userPatternFormatArray.length;
>                   curUserPattern++) {
>                  // Retrieve user information
>  -                User user = getUser(context, username);
>  +                User user = getUser(context, username, credentials, curUserPattern);
>                  if (user != null) {
>                      try {
>                          // Check the user's credentials
>                          if (checkCredentials(context, user, credentials)) {
>                              // Search for additional roles
>                              List<String> roles = getRoles(context, user);
>  +                            if (containerLog.isDebugEnabled()) {
>  +                                Iterator<String> it = roles.iterator();
>  +                                while (it.hasNext()) {
>  +                                    containerLog.debug("Found role: " + it.next());
>  +                                }
>  +                            }
>                              return (new GenericPrincipal(this,
>                                                           username,
>                                                           credentials,
>  @@ -940,7 +1043,7 @@
>              return null;
>          } else {
>              // Retrieve user information
>  -            User user = getUser(context, username);
>  +            User user = getUser(context, username, credentials);
>              if (user == null)
>                  return (null);
>
>  @@ -950,6 +1053,12 @@
>
>              // Search for additional roles
>              List<String> roles = getRoles(context, user);
>  +            if (containerLog.isDebugEnabled()) {
>  +                Iterator<String> it = roles.iterator();
>  +                while (it.hasNext()) {
>  +                    containerLog.debug("Found role: " + it.next());
>  +                }
>  +            }
>
>              // Create and return a suitable Principal for this user
>              return (new GenericPrincipal(this, username, credentials, roles));
>  @@ -962,6 +1071,45 @@
>       * with the specified username, if found in the directory;
>       * otherwise return <code>null</code>.
>       *
>  +     * @param context The directory context
>  +     * @param username Username to be looked up
>  +     *
>  +     * @exception NamingException if a directory server error occurs
>  +     *
>  +     * @see #getUser(DirContext, String, String, int)
>  +     */
>  +    protected User getUser(DirContext context, String username)
>  +        throws NamingException {
>  +
>  +        return getUser(context, username, null, -1);
>  +    }
>  +
>  +
>  +    /**
>  +     * Return a User object containing information about the user
>  +     * with the specified username, if found in the directory;
>  +     * otherwise return <code>null</code>.
>  +     *
>  +     * @param context The directory context
>  +     * @param username Username to be looked up
>  +     * @param credentials User credentials (optional)
>  +     *
>  +     * @exception NamingException if a directory server error occurs
>  +     *
>  +     * @see #getUser(DirContext, String, int)
>  +     */
>  +    protected User getUser(DirContext context, String username, String credentials)
>  +        throws NamingException {
>  +
>  +        return getUser(context, username, credentials, -1);
>  +    }
>  +
>  +
>  +    /**
>  +     * Return a User object containing information about the user
>  +     * with the specified username, if found in the directory;
>  +     * otherwise return <code>null</code>.
>  +     *
>       * If the <code>userPassword</code> configuration attribute is
>       * specified, the value of that attribute is retrieved from the
>       * user's directory entry. If the <code>userRoleName</code>
>  @@ -970,10 +1118,13 @@
>       *
>       * @param context The directory context
>       * @param username Username to be looked up
>  +     * @param credentials User credentials (optional)
>  +     * @param curUserPattern Index into userPatternFormatArray
>       *
>       * @exception NamingException if a directory server error occurs
>       */
>  -    protected User getUser(DirContext context, String username)
>  +    protected User getUser(DirContext context, String username,
>  +                           String credentials, int curUserPattern)
>          throws NamingException {
>
>          User user = null;
>  @@ -988,8 +1139,8 @@
>          list.toArray(attrIds);
>
>          // Use pattern or search for user entry
>  -        if (userPatternFormatArray != null) {
>  -            user = getUserByPattern(context, username, attrIds);
>  +        if (userPatternFormatArray != null && curUserPattern >= 0) {
>  +            user = getUserByPattern(context, username, credentials, attrIds, curUserPattern);
>          } else {
>              user = getUserBySearch(context, username, attrIds);
>          }
>  @@ -999,29 +1150,24 @@
>
>
>      /**
>  -     * Use the <code>UserPattern</code> configuration attribute to
>  -     * locate the directory entry for the user with the specified
>  -     * username and return a User object; otherwise return
>  -     * <code>null</code>.
>  +     * Use the distinguished name to locate the directory
>  +     * entry for the user with the specified username and
>  +     * return a User object; otherwise return <code>null</code>.
>       *
>       * @param context The directory context
>       * @param username The username
>       * @param attrIds String[]containing names of attributes to
>  +     * @param dn Distinguished name of the user
>       * retrieve.
>       *
>       * @exception NamingException if a directory server error occurs
>       */
>      protected User getUserByPattern(DirContext context,
>  -                                              String username,
>  -                                              String[] attrIds)
>  +                                    String username,
>  +                                    String[] attrIds,
>  +                                    String dn)
>          throws NamingException {
>
>  -        if (username == null || userPatternFormatArray[curUserPattern] == null)
>  -            return (null);
>  -
>  -        // Form the dn from the user pattern
>  -        String dn = userPatternFormatArray[curUserPattern].format(new String[] { username });
>  -
>          // Get required attributes from user entry
>          Attributes attrs = null;
>          try {
>  @@ -1047,6 +1193,71 @@
>
>
>      /**
>  +     * Use the <code>UserPattern</code> configuration attribute to
>  +     * locate the directory entry for the user with the specified
>  +     * username and return a User object; otherwise return
>  +     * <code>null</code>.
>  +     *
>  +     * @param context The directory context
>  +     * @param username The username
>  +     * @param credentials User credentials (optional)
>  +     * @param attrIds String[]containing names of attributes to
>  +     * @param curUserPattern Index into userPatternFormatArray
>  +     *
>  +     * @exception NamingException if a directory server error occurs
>  +     * @see #getUserByPattern(DirContext, String, String[], String)
>  +     */
>  +    protected User getUserByPattern(DirContext context,
>  +                                    String username,
>  +                                    String credentials,
>  +                                    String[] attrIds,
>  +                                    int curUserPattern)
>  +        throws NamingException {
>  +
>  +        User user = null;
>  +
>  +        if (username == null || userPatternFormatArray[curUserPattern] == null)
>  +            return (null);
>  +
>  +        // Form the dn from the user pattern
>  +        String dn = userPatternFormatArray[curUserPattern].format(new String[] { username });
>  +
>  +        try {
>  +            user = getUserByPattern(context, username, attrIds, dn);
>  +        } catch (NameNotFoundException e) {
>  +            return (null);
>  +        } catch (NamingException e) {
>  +            // If the getUserByPattern() call fails, try it again with the
>  +            // credentials of the user that we're searching for
>  +            try {
>  +                // Set up security environment to bind as the user
>  +                context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
>  +                context.addToEnvironment(Context.SECURITY_CREDENTIALS, credentials);
>  +
>  +                user = getUserByPattern(context, username, attrIds, dn);
>  +            } finally {
>  +                // Restore the original security environment
>  +                if (connectionName != null) {
>  +                    context.addToEnvironment(Context.SECURITY_PRINCIPAL,
>  +                                             connectionName);
>  +                } else {
>  +                    context.removeFromEnvironment(Context.SECURITY_PRINCIPAL);
>  +                }
>  +
>  +                if (connectionPassword != null) {
>  +                    context.addToEnvironment(Context.SECURITY_CREDENTIALS,
>  +                                             connectionPassword);
>  +                }
>  +                else {
>  +                    context.removeFromEnvironment(Context.SECURITY_CREDENTIALS);
>  +                }
>  +            }
>  +        }
>  +        return user;
>  +    }
>  +
>  +
>  +    /**
>       * Search the directory to return a User object containing
>       * information about the user with the specified username, if
>       * found in the directory; otherwise return <code>null</code>.
>  @@ -1058,8 +1269,8 @@
>       * @exception NamingException if a directory server error occurs
>       */
>      protected User getUserBySearch(DirContext context,
>  -                                           String username,
>  -                                           String[] attrIds)
>  +                                   String username,
>  +                                   String[] attrIds)
>          throws NamingException {
>
>          if (username == null || userSearchFormat == null)
>  @@ -1083,36 +1294,38 @@
>              attrIds = new String[0];
>          constraints.setReturningAttributes(attrIds);
>
>  -        NamingEnumeration results =
>  +        NamingEnumeration<SearchResult> results =
>              context.search(userBase, filter, constraints);
>
>
>          // Fail if no entries found
>  -        if (results == null || !results.hasMore()) {
>  -            return (null);
>  +        try {
>  +            if (results == null || !results.hasMore()) {
>  +                return (null);
>  +            }
>  +        } catch (PartialResultException ex) {
>  +            if (!adCompat)
>  +                throw ex;
>  +            else
>  +                return (null);
>          }
>
>          // Get result for the first entry found
>  -        SearchResult result = (SearchResult)results.next();
>  +        SearchResult result = results.next();
>
>          // Check no further entries were found
>  -        if (results.hasMore()) {
>  -            if(containerLog.isInfoEnabled())
>  -                containerLog.info("username " + username + " has multiple entries");
>  -            return (null);
>  +        try {
>  +            if (results.hasMore()) {
>  +                if(containerLog.isInfoEnabled())
>  +                    containerLog.info("username " + username + " has multiple entries");
>  +                return (null);
>  +            }
>  +        } catch (PartialResultException ex) {
>  +            if (!adCompat)
>  +                throw ex;
>          }
>
>  -        // Get the entry's distinguished name
>  -        NameParser parser = context.getNameParser("");
>  -        Name contextName = parser.parse(context.getNameInNamespace());
>  -        Name baseName = parser.parse(userBase);
>  -
>  -        // Bugzilla 32269
>  -        Name entryName = parser.parse(new CompositeName(result.getName()).get(0));
>  -
>  -        Name name = contextName.addAll(baseName);
>  -        name = name.addAll(entryName);
>  -        String dn = name.toString();
>  +        String dn = getDistinguishedName(context, userBase, result);
>
>          if (containerLog.isTraceEnabled())
>              containerLog.trace("  entry found for " + username + " with dn " + dn);
>  @@ -1333,7 +1546,6 @@
>          return (validated);
>       }
>
>  -
>      /**
>       * Return a List of roles associated with the given User.  Any
>       * roles present in the user's directory entry are supplemented by
>  @@ -1365,11 +1577,19 @@
>          if (list == null) {
>              list = new ArrayList<String>();
>          }
>  +        if (commonRole != null)
>  +            list.add(commonRole);
>  +
>  +        if (containerLog.isTraceEnabled()) {
>  +            containerLog.trace("  Found " + list.size() + " user internal roles");
>  +            for (int i=0; i<list.size(); i++)
>  +                containerLog.trace(  "  Found user internal role " + list.get(i));
>  +        }
>
>          // Are we configured to do role searches?
>          if ((roleFormat == null) || (roleName == null))
>              return (list);
>  -
>  +
>          // Set up parameters for an appropriate search
>          String filter = roleFormat.format(new String[] { doRFC2254Encoding(dn), username });
>          SearchControls controls = new SearchControls();
>  @@ -1380,30 +1600,86 @@
>          controls.setReturningAttributes(new String[] {roleName});
>
>          // Perform the configured search and process the results
>  -        NamingEnumeration results =
>  +        NamingEnumeration<SearchResult> results =
>              context.search(roleBase, filter, controls);
>          if (results == null)
>              return (list);  // Should never happen, but just in case ...
>  -        while (results.hasMore()) {
>  -            SearchResult result = (SearchResult) results.next();
>  -            Attributes attrs = result.getAttributes();
>  -            if (attrs == null)
>  -                continue;
>  -            list = addAttributeValues(roleName, attrs, list);
>  -        }
>
>  +        HashMap<String, String> groupMap = new HashMap<String, String>();
>  +        try {
>  +            while (results.hasMore()) {
>  +                SearchResult result = 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) {
>  +                    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");
>  -                for (int i=0; i<list.size(); i++)
>  -                    containerLog.trace(  "  Found role " + list.get(i));
>  -            } else {
>  -                containerLog.trace("  getRoles about to return null ");
>  +            containerLog.trace("  Found " + keys.size() + " direct roles");
>  +            for (String key: keys) {
>  +                containerLog.trace(  "  Found direct role " + key + " -> " + groupMap.get(key));
>              }
>          }
>
>  -        return (list);
>  +        // if nested group search is enabled, perform searches for nested groups until no new group is found
>  +        if (getRoleNested()) {
>  +
>  +            // The following efficient algorithm is known as memberOf Algorithm, as described in "Practices in
>  +            // Directory Groups". It avoids group slurping and handles cyclic group memberships as well.
>  +            // See http://middleware.internet2.edu/dir/ for details
>  +
>  +            Set<String> newGroupDNs = new HashSet<String>(groupMap.keySet());
>  +            while (!newGroupDNs.isEmpty()) {
>  +                Set<String> newThisRound = new HashSet<String>(); // Stores the groups we find in this iteration
>  +
>  +                for (String groupDN : newGroupDNs) {
>  +                    filter = roleFormat.format(new String[] { groupDN });
>  +
>  +                    if (containerLog.isTraceEnabled()) {
>  +                        containerLog.trace("Perform a nested group search with base "+ roleBase + " and filter " + filter);
>  +                    }
>  +
>  +                    results = context.search(roleBase, filter, controls);
>  +
>  +                    try {
>  +                        while (results.hasMore()) {
>  +                            SearchResult result = 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 && !groupMap.keySet().contains(dname)) {
>  +                                groupMap.put(dname, name);
>  +                                newThisRound.add(dname);
>  +
>  +                                if (containerLog.isTraceEnabled()) {
>  +                                    containerLog.trace("  Found nested role " + dname + " -> " + name);
>  +                                }
>  +
>  +                            }
>  +                         }
>  +                    } catch (PartialResultException ex) {
>  +                        if (!adCompat)
>  +                            throw ex;
>  +                    }
>  +                }
>  +
>  +                newGroupDNs = newThisRound;
>  +            }
>  +        }
>  +
>  +        return new ArrayList<String>(groupMap.values());
>      }
>
>
>  @@ -1464,10 +1740,15 @@
>          Attribute attr = attrs.get(attrId);
>          if (attr == null)
>              return (values);
>  -        NamingEnumeration e = attr.getAll();
>  -        while(e.hasMore()) {
>  -            String value = (String)e.next();
>  -            values.add(value);
>  +        NamingEnumeration<?> e = attr.getAll();
>  +        try {
>  +            while(e.hasMore()) {
>  +                String value = (String)e.next();
>  +                values.add(value);
>  +            }
>  +        } catch (PartialResultException ex) {
>  +            if (!adCompat)
>  +                throw ex;
>          }
>          return values;
>      }
>  @@ -1599,9 +1880,9 @@
>      protected synchronized Principal getPrincipal(DirContext context,
>                                                    String username)
>          throws NamingException {
>  -
>  +
>          User user = getUser(context, username);
>  -
>  +
>          return new GenericPrincipal(this, user.username, user.password ,
>                  getRoles(context, user));
>      }
>  @@ -1650,7 +1931,7 @@
>       *
>       * @return java.util.Hashtable the configuration for the directory context.
>       */
>  -    protected Hashtable getDirectoryContextEnvironment() {
>  +    protected Hashtable<String,String> getDirectoryContextEnvironment() {
>
>          Hashtable<String,String> env = new Hashtable<String,String>();
>
>  @@ -1689,7 +1970,7 @@
>       */
>      protected void release(DirContext context) {
>
>  -        ; // NO-OP since we are not pooling anything
>  +        // NO-OP since we are not pooling anything
>
>      }
>
>  @@ -1773,7 +2054,7 @@
>                  startingPoint = endParenLoc+1;
>                  startParenLoc = userPatternString.indexOf('(', startingPoint);
>              }
>  -            return (String[])pathList.toArray(new String[] {});
>  +            return pathList.toArray(new String[] {});
>          }
>          return null;
>
>
>  Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
>  URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=812115&r1=812114&r2=812115&view=diff
>  ==============================================================================
>  --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
>  +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Mon Sep  7 12:45:58 2009
>  @@ -155,6 +155,11 @@
>          Correct JDBC driver de-registration on web application stop and fix NPE
>          that is exposed by the fix. (markt)
>        </fix>
>  +      <update>
>  +        Various JNDI realm improvements for Active Directory. These include the
>  +        ability to specify a default role, optional handling for nested roles
>  +        and an option to ignore PartialResultExceptions (markt).
>  +      </update>
>      </changelog>
>    </subsection>
>    <subsection name="Coyote">
>
>
>
>  ---------------------------------------------------------------------
>  To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
>  For additional commands, e-mail: dev-help@tomcat.apache.org
>
>

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