Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DirectorySearcher/LDAP lookup fails from IIS deployment environment, works from console on same machine

We have some code executing in an ASP.NET MVC 4 application. The application is hosted in IIS on Windows Server 2012. The identity of the app-pool is not standard, but rather a specific user, e.g. iis-appPool-username noted below. The application is running in .NET 4.0 w/ Integrated Mode set for the Managed Pipeline.

  • I've tried it both with and without specifying the username in the DirectoryEntry object.
  • I can run a console app that does the same thing, as the very same user (command.exe run as the same user, that is) on the same machine, and it works.
  • It should be noted that the console app did not work until I manually specified the LDAP path and AuthenticationTypes.ReadonlyServer, as it is hitting a read-only domain controller. It was giving me the same error for the console app until I specified the LDAP path and Readonly type. However, while console app works now, while the IIS app does not.

The code is below.

// also tried: var searchRoot = new DirectoryEntry(@"LDAP://DC=subdom,DC=ourdomain,DC=com");
var searchRoot = new DirectoryEntry(@"LDAP://DC=subdom,DC=ourdomain,DC=com", @"domain\iis-appPool-username", "password");
searchRoot.AuthenticationType = AuthenticationTypes.ReadonlyServer;

using (var searcher = new DirectorySearcher(searchRoot))
{
    searcher.Filter = string.Format("(&(objectClass=group)(sAMAccountName={0}))", "someGroupName");
    searcher.PropertiesToLoad.Add("distinguishedName");

    // This is where the failure happens
    var result = searcher.FindOne();
}

The error w/ stack trace looks like this:

System.Runtime.InteropServices.COMException (0x8007054B): 
The specified domain either does not exist or could not be contacted.

at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.PropertyValueCollection.PopulateList()
at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
at System.DirectoryServices.PropertyCollection.get_Item(String propertyName)
at System.DirectoryServices.DirectorySearcher.get_SearchRoot()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()

EDIT: Also, it is the very same error if I explicitly use the wrong username and password. From my local machine, if I use the wrong username and password, I get an auth error. However, from IIS, with the wrong username and password, it doesn't even get that far.

EDIT: I specified in the web.config to run with full trust:

<securityPolicy>
    <trustLevel name="Full" policyFile="internal"/>
</securityPolicy>

And we also gave the user admin priveleges on the box. Continue to get the same error: System.Runtime.InteropServices.COMException: The specified domain either does not exist or could not be contacted.

UPDATE: So, this ended up being a combination of 2 problems.

1) As @Hans noted below, I was originally missing the DirectoryEntry parameter to DirectorySearcher. In my quest to try different possibilities, combinations, I managed to miss that change when I had a working console application and was updating the application code to reflect it.

2) When I added the parameter to DirectorySearcher, I was still getting the error. The message was identical, and the stack trace was almost identical. There was 1 line different in the middle of the stack trace - a secondary call to another method that needed the DirectoryEntry argument to use in it's own DirectorySearcher. I had been looking at the problem for so long, that my eyes were only seeing the same error message and what appeared to be the same stack trace, when in fact it was a new one. Passing my DirectoryEntry object to those calls fixed that problem.

The ultimate solution did not require that I have a server identifier in the path (but your mileage may vary on that if your environment cannot resolve the domain controller without it).

like image 348
Matt Avatar asked Sep 20 '13 21:09

Matt


1 Answers

You have to specify the search root for the DirectorySearcher class in order to connect to the Active Directory domain controller. You will get a COM Exception (0x8007054B) if you do not specify a search root for the DirectorySearcher class.

Try the following lines of code instead:

var searchRoot = new DirectoryEntry(@"LDAP://DC=subdom,DC=ourdomain,DC=com", @"domain\iis-appPool-username", "password");
searchRoot.AuthenticationType = AuthenticationTypes.ReadonlyServer;

using (var searcher = new DirectorySearcher(searchRoot)) // Specify the search root here
{
  searcher.Filter = string.Format("(&(objectClass=group)(sAMAccountName={0}))", "someGroupName");
  searcher.PropertiesToLoad.Add("distinguishedName");

  var result = searcher.FindOne();
}
like image 100
Hans Avatar answered Sep 17 '22 17:09

Hans