UserPrincipal.FindByIdentity 失败并显示 System.Runtime.InteropServices.COMException (0x80005000):未知错误 (0x80005000)
UserPrincipal.FindByIdentity fails with System.Runtime.InteropServices.COMException (0x80005000): Unknown error (0x80005000)
在 Visual Studio 中调试时,下面的代码可以在我的开发机器上运行。开发机器与登台和生产服务器位于不同的域,但使用用户名和密码创建主体上下文似乎解决了我在那里遇到的问题。
当 运行 登台服务器上的 ValidateCredentials 通过但 FindByIdentity() 调用失败并显示以下堆栈跟踪时。
IIS 池 运行 宁作为 ApplicationPoolIdentity 但我认为这应该无关紧要,因为 ValidateCredentials 有效(因此联系域控制器有效)并且 PrincipalContext 是使用有效的用户名和密码创建的域(因此用户池 运行 应该无关紧要)。
我找到了使用 HostingEnvironment.Impersonate() 的建议,但我很确定这不是 .Net 5/Core 的一个选项,因为我将明确的用户名和密码传递给 PrincipalContext 它应该'反正玩不了了。
我找到了 ,我可以尝试创建一个新的应用程序池并将网站移到那里,但我不喜欢“黑魔法”修复,认为它不太可能起作用。
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();
堆栈跟踪:
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
终于想通了!
要么传入一个空字符串与传入 null 不同,要么如果它们是等效的,那么出于某种原因,MS 文档中的以下句子实际上并不适用于此设置,尽管我认为它适用.
我将它设置为 AD 域基础 (client.com),它起作用了。
“””如果域上下文类型的名称为空,则此上下文是线程所在的用户主体域的域控制器 运行。””
在 Visual Studio 中调试时,下面的代码可以在我的开发机器上运行。开发机器与登台和生产服务器位于不同的域,但使用用户名和密码创建主体上下文似乎解决了我在那里遇到的问题。
当 运行 登台服务器上的 ValidateCredentials 通过但 FindByIdentity() 调用失败并显示以下堆栈跟踪时。
IIS 池 运行 宁作为 ApplicationPoolIdentity 但我认为这应该无关紧要,因为 ValidateCredentials 有效(因此联系域控制器有效)并且 PrincipalContext 是使用有效的用户名和密码创建的域(因此用户池 运行 应该无关紧要)。
我找到了使用 HostingEnvironment.Impersonate() 的建议,但我很确定这不是 .Net 5/Core 的一个选项,因为我将明确的用户名和密码传递给 PrincipalContext 它应该'反正玩不了了。
我找到了 ,我可以尝试创建一个新的应用程序池并将网站移到那里,但我不喜欢“黑魔法”修复,认为它不太可能起作用。
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();
堆栈跟踪:
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
终于想通了!
要么传入一个空字符串与传入 null 不同,要么如果它们是等效的,那么出于某种原因,MS 文档中的以下句子实际上并不适用于此设置,尽管我认为它适用.
我将它设置为 AD 域基础 (client.com),它起作用了。
“””如果域上下文类型的名称为空,则此上下文是线程所在的用户主体域的域控制器 运行。””