web-dev-qa-db-fra.com

Active Directory - Vérifier le nom d'utilisateur / mot de passe

J'utilise le code suivant sur Windows Vista Ultimate SP1 pour interroger notre serveur Active Directory pour vérifier le nom d'utilisateur et le mot de passe d'un utilisateur sur un domaine.

public Object IsAuthenticated()
{
    String domainAndUsername = strDomain + "\\" + strUser;
    DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, strPass);
    SearchResult result;
    try
    {
        //Bind to the native AdsObject to force authentication.         

        DirectorySearcher search = new DirectorySearcher(entry) { Filter = ("(SAMAccountName=" + strUser + ")") };

        search.PropertiesToLoad.Add("givenName"); // First Name                
        search.PropertiesToLoad.Add("sn"); // Last Name
        search.PropertiesToLoad.Add("cn"); // Last Name

        result = search.FindOne();

        if (null == result)
        {
            return null;
        }

        //Update the new path to the user in the directory.
        _path = result.Path;
        _filterAttribute = (String)result.Properties["cn"][0];
    }
    catch (Exception ex)
    {
        return new Exception("Error authenticating user. " + ex.Message);
    }
    return user;
}

la cible utilise .NET 3.5 et compilée avec la norme VS 2008

Je suis connecté sous un compte de domaine qui est un administrateur de domaine où l'application s'exécute.

Le code fonctionne parfaitement sous Windows XP; mais j'obtiens l'exception suivante lors de son exécution sur Vista:

System.DirectoryServices.DirectoryServicesCOMException (0x8007052E): Logon failure: unknown user name or bad password.

   at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
   at System.DirectoryServices.DirectorySearcher.FindOne()
   at Chain_Of_Custody.Classes.Authentication.LdapAuthentication.IsAuthenticated()
   at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
   at System.DirectoryServices.DirectorySearcher.FindOne()
   at Chain_Of_Custody.Classes.Authentication.LdapAuthentication.IsAuthenticated()

J'ai essayé de changer les types d'authentification, je ne sais pas ce qui se passe.


Voir également: Valider un nom d'utilisateur et un mot de passe par rapport à Active Directory?

35
Michael G

Si vous utilisez .net 3.5, utilisez plutôt ce code.

Pour authentifier un utilisateur:

PrincipalContext adContext = new PrincipalContext(ContextType.Domain);

using (adContext)
{
     return adContext.ValidateCredentials(UserName, Password);
}

Si vous devez rechercher les attributs utilisateur/R/W de l'objet, procédez comme suit:

PrincipalContext context = new PrincipalContext(ContextType.Domain);
UserPrincipal foundUser = 
    UserPrincipal.FindByIdentity(context, "jdoe");

Ceci utilise l'espace de noms System.DirectoryServices.AccountManagement, vous devrez donc l'ajouter à vos instructions using.

Si vous devez convertir un objet UserPrincipal en un objet DirectoryEntry pour travailler avec du code hérité, vous pouvez le faire:

DirectoryEntry userDE = (DirectoryEntry)foundUser.GetUnderlyingObject();
50
Steve Evans

J'ai trouvé ce même code flottant sur Internet sur plusieurs sites Web et cela n'a pas fonctionné pour moi. Steve Evans a probablement raison de dire que si vous êtes sur .NET 3.5, vous ne devriez pas utiliser ce code. Mais si vous êtes toujours sur .NET 2.0, vous pouvez essayer ceci pour vous authentifier auprès de vos services AD:

DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, 
   userName, password, 
   AuthenticationTypes.Secure | AuthenticationTypes.SecureSocketsLayer);
object nativeObject = entry.NativeObject;

La première ligne crée un objet DirectoryEntry à l'aide du domaine, du nom d'utilisateur et du mot de passe. Il définit également les AuthenticationTypes. Remarquez comment je configure à la fois l'authentification sécurisée (Kerberos) et SSL à l'aide de l'opérateur "Bitwise OR" ('|') entre les deux paramètres.

La deuxième ligne force le NativeObject de "entry" à se lier aux services AD en utilisant les informations de la première ligne.

Si une exception est levée, les informations d'identification (ou paramètres) étaient incorrectes. Si aucune exception, vous êtes authentifié. Le message d'exception indique généralement ce qui n'a pas fonctionné.

Ce code est assez similaire à ce que vous avez déjà, mais le domaine est utilisé là où vous avez "chemin" et le nom d'utilisateur n'est pas combiné avec le domaine. Veillez également à définir correctement vos AuthenticationTypes. Cela peut rendre ou casser la capacité d'authentification.

8
Pretzel

Je l'ai compris de toute façon Si vous passez dans le domaine avec le nom d'utilisateur sur Vista, cela ne fonctionne pas comme "domaine\utilisateur", donc le simple fait de passer "utilisateur" semble fonctionner correctement - sauf que vous devez être sur le même domaine

1
Michael G

La liaison à LDAP nécessite-t-elle des privilèges élevés (UAC)? Vous pouvez essayer d'exécuter Visual Studio et/ou l'application en tant qu'administrateur et voir si cela aide. Si tel est le problème, vous pouvez toujours ajouter un manifeste à l'application et le définir pour qu'il nécessite une élévation, de cette façon, il vous demandera lorsqu'un utilisateur l'exécute.

Je ne sais pas pourquoi cela nécessiterait des privations élevées, mais ça vaut le coup.

0
Steven Robbins