При тестировании нашего приложения .NET 4.0 в .NET 4.5 у нас возникла проблема с методом FindByIdentity
для UserPrincipal
. Следующий код работает при запуске в среде выполнения .NET 4.0, но не выполняется в .NET 4.5:
[Test]
public void TestIsAccountLockedOut()
{
const string activeDirectoryServer = "MyActiveDirectoryServer";
const string activeDirectoryLogin = "[email protected]";
const string activeDirectoryPassword = "MyADAccountPassword";
const string userAccountToTest = "[email protected]";
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)
Кто-нибудь еще видел и разрешал эту проблему? Если нет, есть ли лучший способ проверить статус IsAccountLockedOut
для учетной записи Active Directory?
Для справки, все наши тестовые машины находятся в одной подсети. Существуют отдельные серверы ActiveDirectory, работающие под управлением Windows Server 2003, 2008 и 2012, в различных функциональных режимах домена (см. Ниже). Код работает с компьютерами с .NET 4.0, но не работает с компьютерами с .NET 4.5.
Три компьютера .NET, на которых мы запускали код,:
- Windows 7 с .NET 4.0
- Windows Vista под управлением .NET 4.5
- Windows Server 2012 с .NET.NET
Серверы Active Directory, которые мы пробовали:
- Windows 2003 с функциональным режимом AD Domain, установленным для Windows 2000, родной
- Windows 2003 с функциональным режимом AD Domain, установленным на Windows Server 2003
- Windows 2008 с функциональным режимом AD Domain, установленным для Windows 2000, родной
- Windows 2008 с функциональным режимом AD Domain, установленным на Windows Server 2003
- Windows 2008 с функциональным режимом AD Domain, установленным на Windows Server 2008
- Windows 2012 с функциональным режимом AD Domain, установленным в Windows 2012
Все эти серверы Active Directory настроены как простой, единственный лес, а клиентские машины не являются частью домена. Они не используются для какой-либо другой функции, кроме как проверять это поведение и не запускают ничего, кроме Active Directory.
EDIT - 9 Окт 2012
Спасибо всем, кто ответил. Ниже приведен клиент командной строки С#, который демонстрирует проблему, и краткое обходное решение, которое мы идентифицировали, что не требовало от нас изменения чего-либо в настройках 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 = "[email protected]";
const string unknownUserAccount = "[email protected]";
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