UserPrincipal.FindByIdentity (System.DirectoryServices.AccountManagement) 中的 .NET 4.5 错误

2024-02-12

在 .NET 4.5 下测试 .NET 4.0 应用程序时,我们遇到了一个问题FindByIdentity方法用于UserPrincipal。以下代码在 .NET 4.0 运行时中运行时有效,但在 .NET 4.5 中运行时失败:

[Test]
public void TestIsAccountLockedOut()
{
    const string activeDirectoryServer = "MyActiveDirectoryServer";
    const string activeDirectoryLogin = "MyADAccount@MyDomain";
    const string activeDirectoryPassword = "MyADAccountPassword";
    const string userAccountToTest = "TestUser@MyDomain";
    const string userPasswordToTest = "WRONGPASSWORD";

    var principalContext = new PrincipalContext(ContextType.Domain, activeDirectoryServer, activeDirectoryLogin, activeDirectoryPassword);

    var isAccountLockedOut = false;
    var isAuthenticated = principalContext.ValidateCredentials(userAccountToTest, userPasswordToTest, principalContext.Options);
    if (!isAuthenticated)
    {
        // System.DirectoryServices.AccountManagement.PrincipalOperationException : Information about the domain could not be retrieved (1355).
        using (var user = UserPrincipal.FindByIdentity(principalContext, IdentityType.UserPrincipalName, userAccountToTest))
        {
            isAccountLockedOut = (user != null) && user.IsAccountLockedOut();
        }
    }
    Assert.False(isAuthenticated);
    Assert.False(isAccountLockedOut);
}

这是异常堆栈跟踪:

System.DirectoryServices.AccountManagement.PrincipalOperationException : Information about the domain could not be retrieved (1355).
at System.DirectoryServices.AccountManagement.Utils.GetDcName(String computerName, String domainName, String siteName, Int32 flags)   at System.DirectoryServices.AccountManagement.ADStoreCtx.LoadDomainInfo()   at 
System.DirectoryServices.AccountManagement.ADStoreCtx.get_DnsDomainName()   at System.DirectoryServices.AccountManagement.ADStoreCtx.GetAsPrincipal(Object storeObject, Object discriminant)   at 
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRefHelper(Type principalType, String urnScheme, String urnValue, DateTime referenceDate, Boolean useSidHistory)   at 
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRef(Type principalType, String urnScheme, String urnValue, DateTime referenceDate)   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)   

还有其他人看到并解决了这个问题吗?如果没有的话,我们有没有更好的方法来检查IsAccountLockedOutActive Directory 帐户的状态?

作为参考,我们所有的测试机器都在同一子网内。有单独的 ActiveDirectory 服务器运行 Windows Server 2003、2008 和 2012,具有各种域功能模式(见下文)。该代码在运行 .NET 4.0 的计算机上运行,​​但在运行 .NET 4.5 的计算机上失败。

我们运行代码的三台 .NET 机器是:
- 运行 .NET 4.0 的 Windows 7
- 运行 .NET 4.5 的 Windows Vista
- 运行 .NET 4.5 的 Windows Server 2012

我们尝试过的 Active Directory 服务器是:
- Windows 2003,AD 域功能模式设置为 Windows 2000 本机
- Windows 2003,AD 域功能模式设置为 Windows Server 2003
- Windows 2008,AD 域功能模式设置为 Windows 2000 本机
- Windows 2008,AD 域功能模式设置为 Windows Server 2003
- Windows 2008,AD 域功能模式设置为 Windows Server 2008
- Windows 2012,AD 域功能模式设置为 Windows 2012

所有这些 Active Directory 服务器都配置为简单的单一林,并且客户端计算机不属于域。除了测试此行为之外,它们不用于任何其他功能,并且不运行除 Active Directory 之外的任何内容。


编辑 - 2012 年 10 月 9 日

感谢所有回复的人。下面是一个 C# 命令行客户端,它演示了该问题,以及我们确定的短期解决方法,该解决方法不需要我们更改有关 Active Directory 和 DNS 配置的任何内容。看来该异常仅在 PrimaryContext 实例中抛出一次。我们包含了 .NET 4.0 计算机 (Windows 7) 和 .NET 4.5 计算机 (Windows Vista) 的输出。

using System;
using System.DirectoryServices.AccountManagement;

namespace ADBug
{
    class Program
    {
        static void Main(string[] args)
        {
            const string activeDirectoryServer = "MyActiveDirectoryServer";
            const string activeDirectoryLogin = "MyADAccount";
            const string activeDirectoryPassword = "MyADAccountPassword";
            const string validUserAccount = "[email protected] /cdn-cgi/l/email-protection";
            const string unknownUserAccount = "[email protected] /cdn-cgi/l/email-protection";

            var principalContext = new PrincipalContext(ContextType.Domain, activeDirectoryServer, activeDirectoryLogin, activeDirectoryPassword);

            // .NET 4.0 - First attempt with a valid account finds the user
            // .NET 4.5 - First attempt with a valid account fails with a PrincipalOperationException
            TestFindByIdentity(principalContext, validUserAccount, "Valid Account - First Attempt");
            // Second attempt with a valid account finds the user
            TestFindByIdentity(principalContext, validUserAccount, "Valid Account - Second Attempt");
            // First attempt with an unknown account does not find the user
            TestFindByIdentity(principalContext, unknownUserAccount, "Unknown Account - First Attempt");
            // Second attempt with an unknown account does not find the user (testing false positive)
            TestFindByIdentity(principalContext, unknownUserAccount, "Unknown Account - Second Attempt");
            // Subsequent attempt with a valid account still finds the user
            TestFindByIdentity(principalContext, validUserAccount, "Valid Account - Third Attempt");
        }

        private static void TestFindByIdentity(PrincipalContext principalContext, string userAccountToTest, string message)
        {
            var exceptionThrown = false;
            var userFound = false;
            try
            {
                using (var user = UserPrincipal.FindByIdentity(principalContext, IdentityType.UserPrincipalName, userAccountToTest))
                {
                    userFound = (user != null);
                }
            }
            catch (PrincipalOperationException)
            {
                exceptionThrown = true;
            }
            Console.Out.WriteLine(message + " - Exception Thrown  = {0}", exceptionThrown);
            Console.Out.WriteLine(message + " - User Found = {1}", userAccountToTest, userFound);
        }
    }
}

.NET 4.0 输出

Valid Account - First Attempt - Exception Thrown  = False
Valid Account - First Attempt - User Found = True
Valid Account - Second Attempt - Exception Thrown  = False
Valid Account - Second Attempt - User Found = True
Unknown Account - First Attempt - Exception Thrown  = False
Unknown Account - First Attempt - User Found = False
Unknown Account - Second Attempt - Exception Thrown  = False
Unknown Account - Second Attempt - User Found = False
Valid Account - Third Attempt - Exception Thrown  = False
Valid Account - Third Attempt - User Found = True

.NET 4.5 输出

Valid Account - First Attempt - Exception Thrown  = True
Valid Account - First Attempt - User Found = False
Valid Account - Second Attempt - Exception Thrown  = False
Valid Account - Second Attempt - User Found = True
Unknown Account - First Attempt - Exception Thrown  = False
Unknown Account - First Attempt - User Found = False
Unknown Account - Second Attempt - Exception Thrown  = False
Unknown Account - Second Attempt - User Found = False
Valid Account - Third Attempt - Exception Thrown  = False
Valid Account - Third Attempt - User Found = True

我们遇到了完全相同的问题(跨域查询更新到 4.5 时失败) - 我认为这是一个错误,因为它破坏了现有的(4.0)代码。

然而,为了使其正常工作 - 查看一个(现在)失败的客户端,我注意到有一堆对 SRV 记录的 DNS 请求失败,其形式为:

_ldap._tcp.MYSERVER1.mydomain.com,INet,Srv
_ldap._tcp.dc._msdcs.mydomain.com,INet,Srv

修改我们的 DNS 服务器(失败的客户端使用的 DNS),为所有 mydomain.com 流量提供一个转发区域到域中的 DC 之一,确实解决了该问题。

使用 nslookup,从之前(失败时)到现在(工作)的行为是,在这些查询之前将返回“不存在的域”,而现在它们返回“*没有可用的服务位置 (SRV) 记录...”。故障点似乎是感知到域不存在,而不是丢失 SRV 记录。希望 MS 恢复此行为,但与此同时,您可能会幸运地创建 DNS如果您可以控制失败客户端的 DNS,则转发区域。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UserPrincipal.FindByIdentity (System.DirectoryServices.AccountManagement) 中的 .NET 4.5 错误 的相关文章

随机推荐