I've an MVC Intranet app that I've recently upgraded from .Net 4 to 4.6.1. This app queries user details from Active Directory to load details that aren't available in the Controller's User.Identity property and until lately has done so flawlessly. The code looks something like this:
public static void foo()
{
var usr = LookupUser("MyDomain", "jbloggs");
...
}
private static UserPrincipal LookupUser(string domain, string username)
{
Console.WriteLine($"Lookup {domain}\\{username}");
using (var ctx = new PrincipalContext(ContextType.Domain, domain))
{
using (var user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username))
{
if (user == null)
{
Console.WriteLine("User not found");
return;
}
Console.WriteLine($"Found {domain}\\{username}");
Console.WriteLine($"DisplayName = {user.DisplayName}");
Console.WriteLine($"Office = {user.GetString("physicalDeliveryOfficeName")}");
Console.WriteLine("");
return user;
}
}
}
The code runs fine when debugging in Visual Studio 2015, but when it's running on the IIS box (v6.1 SP1 on Windows Server 2008 R2), throws a COMException (0x80005000) when calling UserPrincipal.FindByIdentity()
The web app is running on a dedicated App Pool, the settings for which are as follows:
- .Net Framework Version = v4.0
- Identity = MyDomain\MyAppServiceUser (Non-interactive AD User Account)
- Load User Profile = false
All other settings are as per the defaults. The application itself is running with both Anonymous and Windows Authentication enabled. The server has .Net 4.6.1 installed and all other elements of the intranet app seem to be running just fine.
Having googled this to death, most of the answers seem to indicate that it's a problem with the service account's permissions to query AD. In order to confirm that the service account that the App Pool is running as DOES have access to query Active Directory, I've used the above code in a console app and run it as both myself and the service account on the server - in both instances it works just fine. It only bombs out when running under IIS.
I've tried numerous variations creating the PrincipalContext (including the OU container path, etc) but the results are always the same.
I'm doing my nut on this, so any help would be greatly appreciated.
Update - additional details
- Exception Type: System.Runtime.InteropServices.COMException
- Exception Message: Unknown error (0x80005000)
- Stack Trace:
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.AccountManagement.PrincipalContext.DoLDAPDirectoryInitNoContainer() at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit() at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize() at System.DirectoryServices.AccountManagement.PrincipalContext.get_QueryCtx() at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate) at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, IdentityType identityType, String identityValue) at System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext context, IdentityType identityType, String identityValue) at Apollo.Security.ActiveDirectoryUser.Find(String identityName)