Вопрос по c#, authentication, .net, active-directory, .net-4.5 – Ошибка 4.5 .NET в UserPrincipal.FindByIdentity (System.DirectoryServices.AccountManagement)

28

При тестировании нашего приложения .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 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 настроены как простой одиночный лес, и клиентские компьютеры не являются частью домена. Они не используются для каких-либо других функций, кроме как для проверки этого поведения, и нене запускать ничего, кроме Active Directory.

РЕДАКТИРОВАТЬ - 9 октября 2012

Спасибо всем, кто ответил. Ниже показан клиент командной строки 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 = "[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
Не уверен, что тыЯ пока гуглил это, но я нашел пост с несколькими комментариями для исправлений для различных сценариев, которые могут вызвать это:elegcode.com/2009/03/21/… I 'Я никогда не видел это сам, но в интересах быть полезным, я думал, чтоЯ поделюсь этим, поскольку это выглядит полезным для меня. David
и просто добавим - наши контроллеры домена win2k8r2 на функциональном уровне win2k8 r2, наши клиенты также являются машинами win2k8r2. bkr
Для чего этоСтоит отметить, что ваш код работал нормально на моей машине, скомпилированной в .NET 4.5. Является ли [email protected] администратором домена? CodeGrue
Я переправил эту проблему в группу разработчиков продукта Microsoft. Кто-нибудь свяжется с вами в начале следующей недели. Anand

Ваш Ответ

3   ответа
5

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

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

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

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

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

Хороший!! попробуй поймать'Дважды сработал вызов FindByIdentity ()! -Спасибо Lin-Art
Я не уверен, если это связано, но мыУ нас всегда были значительные проблемы с производительностью при использовании имен серверов (например, myserver) вместо IP-адресов (например, 192.168.14.3) для сервера. У нас нетЯ не тестировал производительность для решения этой проблемы, но яДавайте скомпонуем контрольный пример и посмотрим, какие цифры мы придумаем. Grand Avenue Software
Спасибо за ответ. Мы подтвердили то же самое поведение (первая попытка не удалась, все последующие были успешными) и опубликовали тестовый клиент выше. Последний отзыв, который мы получили от Microsoft, был следующим:В SDS.AM в .Net4.5 добавлено ограничение, требующее разрешения DNS домена на стороне клиента. Это было разработано, так как в наилучшей практике DNS должна быть правильная запись DNS. Исходя из отзывов с форума, мы рассматриваем возможность снятия ограничения в будущем выпуске ». Grand Avenue Software
Спасибо! Одна вещь, которую я также заметил, заключается в том, что после добавления первой попытки происходит сбой - есть также значительная задержка при любых вызовах в AD - разговор 3 минуты +. Есть ли какие-либо записи для моих локальных хостов, которые я могу добавить, чтобы решить эту проблему? Еще раз спасибо за отзыв! jkat98
12

вляются до 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 на один из контроллеров домена в этом разделе, решило проблему.

Используя nslookup, поведение от прежнего (когда оно терпело неудачу) до настоящего времени (работающего) было таковым, прежде чем эти запросы вернутся "Несуществующий домен " тогда как теперь они возвращаются "* Записи службы местоположения (SRV) недоступны для ... », Похоже, что причиной отказа является предполагаемое отсутствие домена, а не отсутствие записей SRV. Надеюсь, MS отменит это поведение, но в то же время вам может повезти, если вы создадите зону пересылки DNS, если сможете управлять DNS для сбойных клиентов.

0

Возникла такая же проблема после обновления .net Framework с 4.0 до 4.5. Я переместил инфраструктуру на .net 4.5.1, и она заработала.

Я начал новую тему здесьstackoverflow.com/questions/52242019/... mittal
У меня похожая проблема сIsMemberOf() метод. Моя версия .net 4.5.2, но DNS кажется жестким требованием, которое мои тестовые машины не могли выполнить. Любое решение? mittal

Похожие вопросы