Delegation and LDAP
A customer had a requirement to pull pieces of information about the browser user from AD in their web application. Accessible to the web application is the browser user's alias and the domain that the browser user belongs to.
The customer achieves this in their development environment by doing a serverless bind to AD and using a DirectorySearcher object to look up the entry corresponding to the user. The following is sample code which illustrates what I mean:
string ldapPath = "LDAP://" + userDomain;
DirectoryEntry rootEntry = new DirectoryEntry(ldapPath);
using (DirectorySearcher ds = new DirectorySearcher(rootEntry, "(samAccountName=" + userName + ")"))
{
SearchResult result = ds.FindOne();
if (result != null)
{
ResultPropertyValueCollection resultValues = result.Properties["displayName"];
if (resultValues.Count > 0)
{
Label1.Text = (string) resultValues[0];
}
else
{
Label1.Text = "No display name";
}
}
}
Upon migration of the application to the production environment, the application fails with a COM exception error code of 0x80072020. What could be the issue?
When the customer accesses the web page at the web server, the customer does not encounter the error. When the customer sets the authentication of the web application to Basic Authentication and browses the web page from a remote machine, the web page also worked as expected after entering correct credentials.
This evidence would suggest a Kerberos Delegation issue.
However, the web application also accesses SQL server. We obtained SQL Server Profiler traces of the access and we were able to determine that the access is made under the browser user's account. We were able to deduce from this that the issue is isolated to accessing AD via Kerberos Delegation.
The source of the issue is that the userDomain parameter supplied is the netbios name of the user's domain. What you should specify in the LDAP bind string is the Fully Qualified Domain Name (FQDN) of the domain. In other words, you should use an LDAP bind string of the form LDAP://<FQDN>. For example, LDAP://department.company.com. This is best practice and is essential for Kerberos Delegation to work against AD.
If you want to determine the FQDN of a domain programmatically, the following sample code may assist:
DirectoryEntry rootEntry = new DirectoryEntry("LDAP://" + userDomain + "/RootDSE");
string strRoot = rootEntry.Properties["defaultNamingContext"].Value.ToString();
string strFQDN = Regex.Replace(Regex.Replace(strRoot, @"DC=", ""),",",".");
RootDSE allows Anonymous binds and gives you a means of obtaining the appropriate designations for objects in AD that you can use in your LDAP bind strings. The following articles explain RootDSE and may assist you with your choice of a method to bind to AD:
Serverless Binding and RootDSE
Binding to Active Directory
Binding to the Global Catalog
If you are still encountering the symptoms that my customer experienced after changing the LDAP bind string to use the FQDN designation of the domain, seek the assistance of an expert in the domain or network infrastructure of your environment. This person is likely to be able to assist you with the correct FQDN to use and/or assist you in determining the FQDN dynamically.