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/09/19 23:23:22 UTC

svn commit: r697248 - in /tomcat/trunk: java/org/apache/catalina/realm/JNDIRealm.java webapps/docs/config/realm.xml webapps/docs/realm-howto.xml

Author: rjung
Date: Fri Sep 19 14:23:22 2008
New Revision: 697248

URL: http://svn.apache.org/viewvc?rev=697248&view=rev
Log:
Improve Active Directory compatibility of the JNDIRealm.

AD often returns referrals and when iterating through
NamingEnumerations those produce PartialResultsException
we need to ignore. Since there is no robust way of detecting
whether they are actually thrown because of AD referrals,
we keep the handling configurable.

Modified:
    tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java
    tomcat/trunk/webapps/docs/config/realm.xml
    tomcat/trunk/webapps/docs/realm-howto.xml

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=697248&r1=697247&r2=697248&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/JNDIRealm.java Fri Sep 19 14:23:22 2008
@@ -23,6 +23,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 
 import javax.naming.Context;
@@ -35,6 +36,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;
@@ -228,9 +230,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;
+
+
+    /**
+     * 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;
 
@@ -500,6 +513,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 () {
@@ -948,6 +978,12 @@
                         if (checkCredentials(context, user, credentials)) {
                             // Search for additional roles
                             List<String> roles = getRoles(context, user);
+                            if (containerLog.isDebugEnabled()) {
+                                Iterator it = roles.iterator();
+                                while (it.hasNext()) {
+                                    containerLog.debug("Found role: " + it.next());
+                                }
+                            }
                             return (new GenericPrincipal(this,
                                                          username,
                                                          credentials,
@@ -976,6 +1012,12 @@
 
             // Search for additional roles
             List<String> roles = getRoles(context, user);
+            if (containerLog.isDebugEnabled()) {
+                Iterator 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));
@@ -1114,18 +1156,30 @@
 
 
         // 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();
 
         // 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
@@ -1412,12 +1466,17 @@
             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);
+        try {
+            while (results.hasMore()) {
+                SearchResult result = (SearchResult) results.next();
+                Attributes attrs = result.getAttributes();
+                if (attrs == null)
+                    continue;
+                list = addAttributeValues(roleName, attrs, list);
+            }
+        } catch (PartialResultException ex) {
+            if (!adCompat)
+                throw ex;
         }
 
 
@@ -1493,9 +1552,14 @@
         if (attr == null)
             return (values);
         NamingEnumeration e = attr.getAll();
-        while(e.hasMore()) {
-            String value = (String)e.next();
-            values.add(value);
+        try {
+            while(e.hasMore()) {
+                String value = (String)e.next();
+                values.add(value);
+            }
+        } catch (PartialResultException ex) {
+            if (!adCompat)
+                throw ex;
         }
         return values;
     }

Modified: tomcat/trunk/webapps/docs/config/realm.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/realm.xml?rev=697248&r1=697247&r2=697248&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/realm.xml (original)
+++ tomcat/trunk/webapps/docs/config/realm.xml Fri Sep 19 14:23:22 2008
@@ -292,17 +292,27 @@
     information from the directory:</p>
 
     <attributes>
-       <attribute name="alternateURL" required="false">
-         <p>If a socket connection can not be made to the provider at
-         the <code>connectionURL</code> an attempt will be made to use the
-         <code>alternateURL</code>.</p>
-       </attribute>
-
-       <attribute name="authentication" required="false">
-         <p>A string specifying the type of authentication to use.
-         "none", "simple", "strong" or a provider specific definition
-         can be used. If no value is given the providers default is used.</p>
-       </attribute>
+
+      <attribute name="adCompat" required="false">
+        <p>Microsoft Active Directory often returns referrals.
+        When iterating over NamingEnumerations these lead to
+        PartialResultExceptions. If you want us to ignore those exceptions,
+        set this attribute to "true". Unfortunately there's no stable way
+        to detect, if the Exceptions really come from an AD referral.
+        The default value is "false".</p>
+      </attribute>
+
+      <attribute name="alternateURL" required="false">
+        <p>If a socket connection can not be made to the provider at
+        the <code>connectionURL</code> an attempt will be made to use the
+        <code>alternateURL</code>.</p>
+      </attribute>
+
+      <attribute name="authentication" required="false">
+        <p>A string specifying the type of authentication to use.
+        "none", "simple", "strong" or a provider specific definition
+        can be used. If no value is given the providers default is used.</p>
+      </attribute>
 
       <attribute name="commonRole" required="false">
         <p>A role name assigned to each successfully authenticated user in
@@ -336,7 +346,7 @@
         to acquire our JNDI <code>InitialContext</code>.  By default,
         assumes that the standard JNDI LDAP provider will be utilized.</p>
       </attribute>
-      
+
       <attribute name="derefAliases" required="false">
         <p>A string specifying how aliases are to be dereferenced during
         search operations. The allowed values are "always", "never",
@@ -357,6 +367,16 @@
          the providers default is used.</p>
       </attribute>
 
+      <attribute name="referrals" required="false">
+        <p>How do we handle JNDI referrals? Allowed values are
+        "ignore", "follow", or "throw"  (see javax.naming.Context.REFERRAL
+        for more information).
+        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.</p>
+      </attribute>
+
       <attribute name="roleBase" required="false">
         <p>The base directory entry for performing role searches. If
         not specified the top-level element in the directory context

Modified: tomcat/trunk/webapps/docs/realm-howto.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/realm-howto.xml?rev=697248&r1=697247&r2=697248&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/realm-howto.xml (original)
+++ tomcat/trunk/webapps/docs/realm-howto.xml Fri Sep 19 14:23:22 2008
@@ -847,6 +847,15 @@
     "<code>org.apache.catalina.realm.JNDIRealm</code>" here.</p>
   </attribute>
 
+      <attribute name="adCompat" required="false">
+        <p>Microsoft Active Directory often returns referrals.
+        When iterating over NamingEnumerations these lead to
+        PartialResultExceptions. If you want us to ignore those exceptions,
+        set this attribute to "true". Unfortunately there's no stable way
+        to detect, if the Exceptions really come from an AD referral.
+        The default value is "false".</p>
+      </attribute>
+
       <attribute name="alternateURL" required="false">
         <p>If a socket connection can not be made to the provider at
         the <code>connectionURL</code> an attempt will be made to use the
@@ -904,6 +913,16 @@
         specified</p>
       </attribute>
 
+      <attribute name="referrals" required="false">
+        <p>How do we handle JNDI referrals? Allowed values are
+        "ignore", "follow", or "throw"  (see javax.naming.Context.REFERRAL
+        for more information).
+        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.</p>
+      </attribute>
+
       <attribute name="protocol" required="false">
          <p>A string specifying the security protocol to use. If not given
          the providers default is used.</p>



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