Подтвердить что ты не робот

Ошибка .NET 4.5 в UserPrincipal.FindByIdentity(System.DirectoryServices.AccountManagement)

При тестировании нашего приложения .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
4b9b3361

Ответ 1

Мы сталкиваемся с одной и той же проблемой (с ошибками перекрестных доменных запросов при обновлении до 4.5). Я считаю это ошибкой, так как она нарушает существующий (4.0) код.

Однако, в интересах заставить его работать - взглянув на одного из (сейчас) неработающих клиентов, я заметил, что существует куча DNS-запросов для записей SRV, которые были неудачными, формы:

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

Изменение нашего DNS-сервера (DNS, используемого отказавшими клиентами), чтобы иметь передовую зону для всего трафика mydomain.com для одного из DC в домене, решила проблему.

Используя nslookup, поведение от ранее (когда оно было неудачно) до настоящего времени (работа) состояло в том, что до того, как эти запросы вернут "несуществующий домен", в то время как теперь они возвращают записи "No Service location (SRV)"...". Точка отказа, по-видимому, является воспринимаемым отсутствием домена, а не отсутствием записей SRV. Надеюсь, MS отменит это поведение, но в то же время вам может быть повезло создать зону переадресации DNS, если вы можете контролировать DNS для отказоустойчивых клиентов.

Ответ 2

Для OP (и всех, кто помогал с ответами) у нас была одна и та же самая проблема. В нашей среде разработки установлен VS2012 и наше приложение нарушилось во время работы во время входа в систему (проблема с AD, как указано выше). Таким образом, у меня была моя система, и я продолжал использовать 2010 год, все время проливая слезы каждый раз, когда Id читал новое сообщение в блоге о том, как ужасный 2012 год - это бла-бла.

Итак, я нашел эту тему благодаря Скотту Хансельману. Я установил виртуальную машину в своем окне разработки, предварительный просмотр разработчика Windows 8 на 90 дней и VS2012. Получил наше приложение и работал и сразу же попал в ловушку AD AD. Просто заверните наш FindByIdentity в попытке поймать и заставили его попробовать еще раз после первого улова - и альт он работает!! Так что благодаря тому, кто понял этот маленький трюк!

Итак, это незначительное исправление и "взлом", который работает для локальной разработки, и не должен влиять на производство, так как мы не собираемся добавлять 4.5 в производство в ближайшее время.

Но недостатком является то, что локально вход в систему теперь занимает примерно 2 минуты против секунд, когда мы работали в 2010 году: (

Я действительно не знаю, что еще я могу предоставить, чтобы попытаться помочь в решении этой ситуации, но все равно решил поделиться своими 2 центами, так как это все еще кажется серьезной проблемой.

Ответ 3

Была такая же проблема после обновления .net framework от 4.0 до 4.5 У меня есть ogpraded framework для .net 4.5.1, и он сработал.