【发布时间】:2012-09-18 12:09:20
【问题描述】:
在.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)
有没有其他人看到并解决了这个问题?如果没有,我们是否有更好的方法来检查 Active Directory 帐户的IsAccountLockedOut 状态?
作为参考,我们所有的测试机器都在同一个子网内。有不同的 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 服务器是:
- 将 AD 域功能模式设置为 Windows 2000 本机的 Windows 2003
- 将 AD 域功能模式设置为 Windows Server 2003 的 Windows 2003
- 将 AD 域功能模式设置为 Windows 2000 本机的 Windows 2008
- 将 AD 域功能模式设置为 Windows Server 2003 的 Windows 2008
- 将 AD 域功能模式设置为 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);
}
}
}
.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
【问题讨论】:
-
不确定您是否已经在 google 上搜索过,但我发现了一篇包含几个 cmets 的帖子,用于修复可能导致此问题的各种场景:elegantcode.com/2009/03/21/… 我自己从未见过,但在有兴趣提供帮助,我想我会分享这个,因为它看起来对我有用。
-
例如您是否尝试过传入 DC 和 CN 例如 PrincipalContext ctx = new PrincipalContext( ContextType.Domain, "fabrikam.com", "CN=Users,DC=fabrikam,DC=com", "管理员", "securelyStoredPassword");
-
DJ,我们刚刚尝试传入 CN & DC 字符串,在 .NET 4.0 下仍然有效,在 .NET 4.5 下失败。
-
只是想确认您不是唯一遇到此问题的人。我有一段几乎相同的代码,它在 FindByIdentity 处引发了相同的异常。我已经在三台具有相同网络设置的计算机上运行它,只有一台具有 .NET 4.5 的计算机出现故障。我不会很快将错误声明为外部错误,但它在升级之前确实有效。
-
我也确认了这个问题。使用 vmware 快照反弹系统前/后 .net 4.5 安装,以验证问题开始的时间。我们还从不在被查询域上的机器进行查询。简单地安装 .net 4.5 会导致工作代码开始无法针对 .net 4 或 4.5。我们正在使用针对 .net 4.0 的 vs2010。将目标更改为 3.5,代码甚至在 4.5 安装后也能正常工作。
标签: c# .net authentication active-directory .net-4.5