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

Gra*_*are 29 .net c# authentication active-directory .net-4.5

在.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);
}
Run Code Online (Sandbox Code Playgroud)

这是异常堆栈跟踪:

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)   
Run Code Online (Sandbox Code Playgroud)

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

作为参考,我们所有的测试机器都在同一个子网内.运行Windows Server 2003,2008和2012的单独ActiveDirectory服务器具有各种域功能模式(见下文).该代码适用于运行.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服务器是:
- 将AD域功能模式设置为Windows 2000本机的
Windows 2003 - 将AD域功能模式设置为Windows Server 2003的
Windows 2003 - 将AD域功能模式设置为Windows 2000本机的Windows 2008
-将AD域功能模式设置为Windows Server 2003的
Windows 2008 - 将Windows域功能模式设置为Windows Server 2008的
Windows 2008 - 将AD域功能模式设置为Windows 2012的Windows 2012

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


编辑 - 2012年10月9日

感谢所有回复的人.下面是一个演示此问题的C#命令行客户端,以及我们发现的短期解决方法,它不需要我们更改有关Active Directory和DNS配置的任何信息.似乎只有PrincipalContext的实例抛出异常一次.我们包括.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 = "TestUser@MyDomain.com";
            const string unknownUserAccount = "UnknownUser@MyDomain.com";

            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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)

bkr*_*bkr 12

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

但是,为了使它工作 - 看看其中一个(现在)失败的客户端,我注意到有一堆DNS请求失败的SRV记录,形式如下:

_ldap._tcp.MYSERVER1.mydomain.com,INet,Srv
_ldap._tcp.dc._msdcs.mydomain.com,INet,Srv
Run Code Online (Sandbox Code Playgroud)

修改我们的DNS服务器(发生故障的客户端使用的DNS)为所有mydomain.com流量提供前向区域到域中的某个DC确实解决了这个问题.

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


jka*_*t98 5

对于OP(以及其他任何帮助回复的人),我们已经(有)同样的问题.在我们的开发环境中,安装的VS2012和我们的应用程序在登录期间在运行时中断(如上所述,AD问题).因此,我的系统已经擦除并继续使用2010年,每次我都会读到一篇关于2012年是多么令人敬畏的新博客帖子时会流下眼泪.

所以我发现这个帖子归功于Scott Hanselman.我在我的开发盒上安装了一个VM,Windows 8开发人员90天预览,以及VS2012.让我们的应用程序启动并运行并立即被登录AD障碍命中.简单地将我们的FindByIdentity包裹在try catch中并强制它在第一次捕获后再次尝试 - 并且中提琴工作!所以,多亏那些想出那个小技巧的人!

因此,它是一个小修复,以及适用于本地开发的"黑客",并且不应该影响生产,因为我们不会很快将4.5投入生产.

但缺点是在本地,登录现在需要2分钟而不是秒,当我们在2010年运行时:(

我真的不知道我还能提供什么来帮助解决这个问题,但无论如何都认为我分享了我的2美分,因为这仍然是一个主要问题.

  • 感谢您的反馈.我们确认了相同的行为(第一次尝试失败,所有后续成功)并在上面发布了一个测试客户端.我们从Microsoft收到的最后反馈如下:_".Net4.5中的SDS.AM在客户端添加了要求域DNS解析的限制.这被设计为DNS最佳实践应该具有正确的DNS条目.基于来自论坛的反馈意见,我们正在考虑取消未来版本中的限制."_ (3认同)