27 votes

Bogue .NET 4.5 dans UserPrincipal.FindByIdentity (System.DirectoryServices.AccountManagement)

Dans le test de notre .NET 4.0 demande en vertu de l' .NET 4.5, nous avons rencontré un problème avec l' FindByIdentity méthode de UserPrincipal. Le code suivant fonctionne lorsque vous exécutez dans un .NET 4.0 de l'exécution, mais ne sous .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);
}

Voici la trace de pile d'exception:

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)   

Quelqu'un d'autre a vu et résolu ce problème? Si non, est-il un meilleur moyen pour nous de vérifier l' IsAccountLockedOut statut pour un compte Active Directory?

Pour référence, l'ensemble de nos machines de test sont dans le même sous-réseau. Il existe des ActiveDirectory des serveurs exécutant Windows Server 2003, 2008 et 2012, dans une variété de domaine fonctionnel modes de fonctionnement (voir ci-dessous). Le code fonctionne à partir de machines en cours d'exécution .NET 4.0, mais ne parvient pas à partir de machines en cours d'exécution .NET 4.5.

Les trois .NET machines, nous avons couru le code sont les suivantes:
- Windows 7 en cours d'exécution .NET 4.0
- Windows Vista en cours d'exécution .NET 4.5
- Windows Server 2012 en cours d'exécution .NET 4.5

Les serveurs Active Directory, nous avons essayé sont:
- Windows 2003 avec AD Fonctionnel de Domaine en Mode natif Windows 2000
- Windows 2003 avec AD Mode Fonctionnel du Domaine Windows Server 2003
- Windows 2008 avec AD Fonctionnel de Domaine en Mode natif Windows 2000
- Windows 2008 avec ANNONCES Mode Fonctionnel du Domaine Windows Server 2003
- Windows 2008 avec ANNONCES Mode Fonctionnel du Domaine Windows Server 2008
- Windows 2012 avec ANNONCES Mode Fonctionnel du Domaine Windows 2012

Tous ceux Active Directory, les serveurs sont configurés comme un simple forêt, et que les machines client ne font pas partie du domaine. Ils ne sont pas utilisé pour toute autre fonction que de tester ce comportement, et ne sont pas en cours d'exécution autre chose que de l'Active Directory.


EDIT - 9 Oct 2012

Merci à tous ceux qui ont répondu. Ci-dessous est un C# client de ligne de commande qui montre le problème, et à court terme de solution de contournement que nous avons identifié que de ne pas nous obliger à changer quoi que ce soit à propos de l'Active Directory et DNS configurations. Il semble que l'exception n'est levée une fois avec une instance de la PrincipalContext. Nous avons inclus les sorties .NET 4.0 machine (Windows 7) et d' .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 Sortie

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 Sortie

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

10voto

bkr Points 697

Nous vivons exactement la même question (croix domaine des requêtes échouent sur la mise à jour 4.5) - je considère que c'est un bug, puisqu'elle brise existant (4.0) du code.

Toutefois, dans l'intérêt de le faire fonctionner - de prendre un coup d'oeil à l'un des (désormais) faute de clients, j'ai remarqué qu'il y avait un tas de requêtes DNS des enregistrements SRV qui ne, de la forme:

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

La modification de notre serveur DNS (DNS utilisé par la faute de clients) pour avoir une zone avant pour tous mydomain.com le trafic vers l'un des contrôleurs de domaine sur le domaine n'a résoudre le problème.

À l'aide de nslookup, le comportement d'avant (quand il n'était pas) maintenant (de travail) est qu'avant que ces requêtes serait de retour "domaine inexistant", alors que maintenant ils reviennent "* Pas d'emplacement de Service (SRV) disponible pour ...". Le point de rupture semble être la perception de la non-existence du domaine plutôt que d'manquant enregistrements SRV. Espérons que MME revient ce problème, mais en attendant, vous pourriez avoir de la chance, la création d'un DNS zone avant si vous pouvez contrôler le DNS pour la faute de clients.

5voto

jkat98 Points 135

Pour l'OP (et toute autre personne qui a aidé avec les réponses), nous avons(eu) le même problème. Dans notre environnement de développement, installé VS2012 et notre application a éclaté au moment de l'exécution lors de la connexion (problème de l'ANNONCE comme l'a souligné ci-dessus). J'ai donc eu mon système effacé et a continué à l'aide de 2010, tout en continuant de verser une larme à chaque fois l'Id de lire un nouveau billet de blog sur la façon impressionnante 2012 est bla bla.

J'ai donc trouvé ce fil grâce à Scott, Hanselman. J'ai installé une VM sur mon développement zone, Windows 8 developer 90day aperçu sur elle, et VS2012. Eu notre Application et en cours d'exécution et a été immédiatement frappé avec le login AD accrocher. Simplement enveloppé nos FindByIdentity dans un try catch et l'oblige à essayer de nouveau après la première capture et alto ça marche!!!! Donc merci à celui qui pensais que peu de truc!!

Par conséquent, une correction mineure, et un "hack" qui œuvre pour le développement local, et ne devrait pas affecter la production puisque nous ne mettons 4.5 sur la production tout moment bientôt.

Mais l'inconvénient est que, localement, l'enregistrement prend maintenant comme 2 minutes versus secondes lorsque nous avons couru sous 2010 :(

Je ne sais pas vraiment ce que je peux fournir à essayer de l'aider à résoudre la situation, mais pensé Id partager mon 2 cents de toute façon puisque cela semble être un problème majeur.

-2voto

Varun Points 226

Je viens de l'équipe .NET Framework - CLR. Nous ne pouvons pas reproduire le problème dans notre machine interne. Elle est probablement liée à quelque chose qui n'est pas présent dans notre environnement interne. Si quelqu'un a une repro à portée de main, seriez-vous prêt à nous permettre de déboguer sur votre machine?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X