import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
import javax.naming.Context;
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;
/**
- * 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;
/**
+ * 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 () {
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,
// 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));
// 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
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;
}
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;
}
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
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",
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
"<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
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>