UserPrincipal.FindByIdentity fails with System.Runtime.InteropServices.COMException (0x80005000): Unknown error (0x80005000)

0

The code below works on my development machine when debugging in Visual Studio. The development machine is on a different domain than the staging and production servers but creating the principal context with a username and password seemed to solve the issues I had there.

When run on the staging server ValidateCredentials passes but the FindByIdentity() calls fails with the stack trace below.

The IIS pool is running as ApplicationPoolIdentity but I don't think that should matter as ValidateCredentials works (so contacting the domain controller works) and the PrincipalContext is created with a valid username and password for the domain (so the user the pool runs as shouldn't matter).

I found suggestions to use HostingEnvironment.Impersonate() but I'm pretty sure that's not an option with .Net 5/Core and as I'm passing an explicit username and password to the PrincipalContext it shouldn't be in play anyway.

I found https://stackoverflow.com/a/39118337/ and I can try creating a new app pool and moving the site there but I don't like "black magic" fixes and think it's rather unlikely to work.

using var principalContext = new PrincipalContext(ContextType.Domain, _activeDirectoryConfiguration.ControllerNameOrIp, username, password);

if (!principalContext.ValidateCredentials(username, password))
{
    _logger.LogWarning(ErrorMessages.UNABLE_TO_AUTHENTICATE + " {0}", username);
    errors.Add("", ErrorMessages.UNABLE_TO_AUTHENTICATE);
    return (null, errors);
}

IEnumerable<string> userGroups;
UserPrincipal adUser;
adUser = UserPrincipal.FindByIdentity(principalContext, username);
userGroups = adUser.GetAuthorizationGroups().Select(x => x.Name).ToList();
DirectoryEntry dirEntry = (DirectoryEntry)adUser.GetUnderlyingObject();
string office = dirEntry.Properties["physicalDeliveryOfficeName"].Value.ToString();

Stack Trace:

System.Runtime.InteropServices.COMException (0x80005000): Unknown error (0x80005000)
   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 XXX.ActiveDirectoryService.Authenticate(String username, String password) in XXX\Services\ActiveDirectoryService.cs:line 55
   at XXX.AuthService.Authenticate(String username, String password) in XXX\Services\AuthService.cs:line 59
.net
iis
active-directory
asked on Stack Overflow Nov 25, 2020 by Jonathan

1 Answer

0

Finally figured this one out!

Either passing in an empty string isn’t the same as passing in null or if it’s equivalent then for some reason the sentence below from the MS docs doesn’t actually apply to the this setup even though I thought it did.

I set it to the AD domain base (client.com) and it worked.

“””If the name is null for a Domain context type this context is a domain controller for the domain of the user principal under which the thread is running.”””

https://docs.microsoft.com/en-us/dotnet/api/system.directoryservices.accountmanagement.principalcontext.-ctor?view=dotnet-plat-ext-5.0#System_DirectoryServices_AccountManagement_PrincipalContext__ctor_System_DirectoryServices_AccountManagement_ContextType_System_String_System_String_System_String_

answered on Stack Overflow Feb 12, 2021 by Jonathan

User contributions licensed under CC BY-SA 3.0