.NET 4.5的bug UserPrincipal.FindByIdentity(System.DirectoryServices.AccountManagement) [英] .NET 4.5 Bug in UserPrincipal.FindByIdentity (System.DirectoryServices.AccountManagement)

查看:566
本文介绍了.NET 4.5的bug UserPrincipal.FindByIdentity(System.DirectoryServices.AccountManagement)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在测试我们的.NET .NET 4.5下4.0应用程序,我们已经遇到了 FindByIdentity 方法 UserPrincipal 。在.NET 4.0运行时上运行时,以下code工作,但.NET 4.5下失败:

  [测试]
公共无效TestIsAccountLockedOut()
{
    常量字符串activeDirectoryServer =MyActiveDirectoryServer;
    常量字符串activeDirectoryLogin =MyADAccount @ MYDOMAIN;
    常量字符串activeDirectoryPassword =MyADAccountPassword;
    常量字符串userAccountToTest =为TestUser @ MYDOMAIN;
    常量字符串userPasswordToTest =WRONGPASSWORD;

    VAR principalContext =新PrincipalContext(ContextType.Domain,activeDirectoryServer,activeDirectoryLogin,activeDirectoryPassword);

    VAR isAccountLockedOut = FALSE;
    VAR isAuthenticated = principalContext.ValidateCredentials(userAccountToTest,userPasswordToTest,principalContext.Options);
    如果(!isAuthenticated)
    {
        // System.DirectoryServices.AccountManagement.PrincipalOperationException:关于无法检索到的域(1355)信息。
        使用(VAR用户= UserPrincipal.FindByIdentity(principalContext,IdentityType.UserPrincipalName,userAccountToTest))
        {
            isAccountLockedOut =(用户!= NULL)&安培;&安培; user.IsAccountLockedOut();
        }
    }
    Assert.False(isAuthenticated);
    Assert.False(isAccountLockedOut);
}
 

下面是异常堆栈跟踪:

  System.DirectoryServices.AccountManagement.PrincipalOperationException:关于域名的信息不能被检索(1355)。
在System.DirectoryServices.AccountManagement.Utils.GetDcName(计算机名字符串,字符串域名,字符串siteName的,的Int32标志)在System.DirectoryServices.AccountManagement.ADStoreCtx.LoadDomainInfo()在
System.DirectoryServices.AccountManagement.ADStoreCtx.get_DnsDomainName()在System.DirectoryServices.AccountManagement.ADStoreCtx.GetAsPrincipal(对象storeObject,对象判别)在
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRefHelper(类型principalType,字符串urnScheme,字符串urnValue,日期时间referenceDate,布尔useSidHistory)在
System.DirectoryServices.AccountManagement.ADStoreCtx.FindPrincipalByIdentRef(类型principalType,字符串urnScheme,字符串urnValue,日期时间referenceDate)在
System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext背景下,类型principalType,Nullable`1 identityType,串identityValue,日期时间refDate)在
System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext背景下,类型principalType,IdentityType identityType,串identityValue)在
System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(PrincipalContext背景下,IdentityType identityType,串identityValue)
 

有其他人看到并解决这个问题呢?如果不是,是给我们检查 IsAccountLockedOut 状态的Active Directory帐户更好的办法?

作为参考,我们所有的测试机器都在同一子网中。有(见下文),运行Windows Server 2003,2008和2012年不同的ActiveDirectory的服务器,在各种域功能模式。在code工作从运行.NET 4.0的机器,但无法从运行.NET 4.5。机

这三个.NET机,我们跑了code是:
- Windows 7中运行.NET 4.0
- Windows Vista中运行的.NET 4.5
- 在Windows Server 2012上运行.NET 4.5

我们已经尝试在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服务器被配置为一个简单的,单一的森林,并在客户端计算机不是域的一部分。它们不用于任何其它功能比来测试此问题,并且尚未运行以外的任何活动目录其它


编辑 - 2011 10月9日

谢谢大家的回答。下面是一个C#命令行客户端,演示了问题,那我们确定,并不需要我们改变有关Active Directory和DNS配置的任何一个短期的解决方法。看来,例外仅与PrincipalContext的实例抛出一次。我们包括了.NET 4.0的机器的输出端(Windows 7中)和.NET 4.5的机器(Windows Vista的)。

 使用系统;
使用System.DirectoryServices.AccountManagement;

命名空间ADBug
{
    类节目
    {
        静态无效的主要(字串[] args)
        {
            常量字符串activeDirectoryServer =MyActiveDirectoryServer;
            常量字符串activeDirectoryLogin =MyADAccount;
            常量字符串activeDirectoryPassword =MyADAccountPassword;
            常量字符串validUserAccount =TestUser@MyDomain.com;
            常量字符串unknownUserAccount =UnknownUser@MyDomain.com;

            VAR principalContext =新PrincipalContext(ContextType.Domain,activeDirectoryServer,activeDirectoryLogin,activeDirectoryPassword);

            // .NET 4.0  - 第一次尝试使用有效帐户查找用户
            // .NET 4.5  - 第一次尝试使用有效帐户失败,出现PrincipalOperationException
            TestFindByIdentity(principalContext,validUserAccount,有效的帐户 - 第一次尝试);
            //第二次尝试使用有效帐户查找用户
            TestFindByIdentity(principalContext,validUserAccount,有效的帐户 - 第二次尝试);
            //第一次尝试与未知帐户没有找到用户
            TestFindByIdentity(principalContext,unknownUserAccount,未知帐户 - 第一次尝试);
            //第二次尝试与未知帐户没有找到用户(检测假阳性)
            TestFindByIdentity(principalContext,unknownUserAccount,未知帐户 - 第二次尝试);
            //随后尝试使用有效帐户还发现用户
            TestFindByIdentity(principalContext,validUserAccount,有效的帐户 - 第三次尝试);
        }

        私有静态无效TestFindByIdentity(PrincipalContext principalContext,串userAccountToTest,字符串消息)
        {
            VAR exceptionThrown = FALSE;
            VAR userFound = FALSE;
            尝试
            {
                使用(VAR用户= UserPrincipal.FindByIdentity(principalContext,IdentityType.UserPrincipalName,userAccountToTest))
                {
                    userFound =(用户!= NULL);
                }
            }
            赶上(PrincipalOperationException)
            {
                exceptionThrown = TRUE;
            }
            Console.Out.WriteLine(信息+ - 抛出的异常= {0},exceptionThrown);
            Console.Out.WriteLine(消息+ - 用户实测值= {1},userAccountToTest,userFound);
        }
    }
}
 

.NET 4.0输出

 有效帐户 - 第一次尝试 - 抛出的异常=假
有效的帐户 - 第一次尝试 - 用户发现= TRUE
有效的帐户 - 第二次尝试 - 抛出的异常=假
有效的帐户 - 第二次尝试 - 用户发现= TRUE
未知帐户 - 第一次尝试 - 抛出的异常=假
未知帐户 - 第一次尝试 - 用户发现=假
未知帐户 - 第二次尝试 - 抛出的异常=假
未知帐户 - 第二次尝试 - 用户发现=假
有效的帐户 - 第三次尝试 - 抛出的异常=假
有效的帐户 - 第三次尝试 - 用户发现= TRUE
 

.NET 4.5输出

 有效帐户 - 第一次尝试 - 抛出的异常=真
有效的帐户 - 第一次尝试 - 用户发现=假
有效的帐户 - 第二次尝试 - 抛出的异常=假
有效的帐户 - 第二次尝试 - 用户发现= TRUE
未知帐户 - 第一次尝试 - 抛出的异常=假
未知帐户 - 第一次尝试 - 用户发现=假
未知帐户 - 第二次尝试 - 抛出的异常=假
未知帐户 - 第二次尝试 - 用户发现=假
有效的帐户 - 第三次尝试 - 抛出的异常=假
有效的帐户 - 第三次尝试 - 用户发现= TRUE
 

解决方案

我们正经历着完全相同的问题(跨域查询失败有关更新至4.5) - 我会认为这是一个错误,因为它打破现有的(4.0)code。

不过,使其工作的兴趣 - 以一看的(现在的)一个失败的客户,我注意到有一堆的SRV记录中都没有的形式,DNS请求:

  _ldap._tcp.MYSERVER1.mydomain.com,INET,SRV
_ldap._tcp.dc._msdcs.mydomain.com,INET,SRV
 

修改我们的DNS服务器(用于失败的客户端的DNS)来对所有mydomain.com流量正向区域在该站点的域控制器的一个根本解决问题。

使用NSLOOKUP,行为与以前(当它不及格)到现在(的工作)是之前的查询将返回域名不存在,而现在他们回来的 * 的无服务的位置(SRV)记录可以......。故障点似乎是域的感知不存在,而不是缺失的SRV记录。希望MS恢复这一行为,但在此期间,你可能有一些运气创建DNS正向区域,如果你能控制的DNS发生故障的客户。

In testing our .NET 4.0 application under .NET 4.5, we've encountered a problem with the FindByIdentity method for UserPrincipal. The following code works when run in a .NET 4.0 runtime, but fails under .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);
}

Here is the exception stack trace:

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)   

Has anyone else seen and resolved this problem? If not, is there a better way for us to check the IsAccountLockedOut status for an Active Directory account?

For reference, all of our test machines are within the same subnet. There are separate ActiveDirectory servers running Windows Server 2003, 2008 and 2012, in a variety of domain functional modes (see below). The code works from machines running .NET 4.0, but fails from machines running .NET 4.5.

The three .NET machines we ran the code from are:
- Windows 7 running .NET 4.0
- Windows Vista running .NET 4.5
- Windows Server 2012 running .NET 4.5

The Active Directory servers we've tried are:
- Windows 2003 with AD Domain Functional Mode set to Windows 2000 native
- Windows 2003 with AD Domain Functional Mode set to Windows Server 2003
- Windows 2008 with AD Domain Functional Mode set to Windows 2000 native
- Windows 2008 with AD Domain Functional Mode set to Windows Server 2003
- Windows 2008 with AD Domain Functional Mode set to Windows Server 2008
- Windows 2012 with AD Domain Functional Mode set to Windows 2012

All of those Active Directory servers are configured as a simple, single forest, and the client machines are not part of the domain. They are not used for any other function than to test this behavior, and aren't running anything other than Active Directory.


EDIT - 9 Oct 2012

Thanks to everyone that replied. Below is a C# command-line client that demonstrates the problem, and a short-term workaround that we identified that didn't require us to change anything about the Active Directory and DNS configurations. It appears that the exception is only thrown once with an instance of the PrincipalContext. We included the outputs for a .NET 4.0 machine (Windows 7) and a .NET 4.5 machine (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);
        }
    }
}

.NET 4.0 Output

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 Output

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

解决方案

We are experiencing the exact same issue (cross domain queries failing on updating to 4.5) - I would consider this a bug since it breaks existing (4.0) code.

However, in the interest of making it work - taking a look at one of the (now) failing clients, I noticed that there were a bunch of DNS requests for SRV records that were failing, of the form:

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

Modifying our DNS server (the DNS used by the failing clients) to have a forward zone for all mydomain.com traffic to one of the DCs on the domain did resolve the issue.

Using nslookup, the behavior from before (when it was failing) to now (working) was that before those queries would return "Non-existent domain" whereas now they return "* No Service location (SRV) records available for ...". The point of failure seems to be the perceived nonexistence of the domain rather than missing SRV records. Hopefully MS reverts this behavior but in the meantime you might have some luck creating a DNS forward zone if you can control the DNS for the failing clients.

这篇关于.NET 4.5的bug UserPrincipal.FindByIdentity(System.DirectoryServices.AccountManagement)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆