Benutzernamen und Passwort gegen Active Directory validieren?

526

Wie kann ich einen Benutzernamen und ein Passwort anhand von Active Directory überprüfen? Ich möchte einfach überprüfen, ob ein Benutzername und ein Passwort korrekt sind.

Marc
quelle

Antworten:

642

Wenn Sie mit .NET 3.5 oder höher arbeiten, können Sie den System.DirectoryServices.AccountManagementNamespace verwenden und Ihre Anmeldeinformationen einfach überprüfen:

// create a "principal context" - e.g. your domain (could be machine, too)
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
{
    // validate the credentials
    bool isValid = pc.ValidateCredentials("myuser", "mypassword");
}

Es ist einfach, es ist zuverlässig, es ist 100% C # -verwalteter Code auf Ihrer Seite - was können Sie mehr verlangen? :-)

Lesen Sie hier alles darüber:

Aktualisieren:

Wie in dieser anderen SO-Frage (und ihren Antworten) beschrieben , gibt es ein Problem mit diesem Aufruf, bei dem möglicherweise Truealte Kennwörter eines Benutzers zurückgegeben werden. Sei dir dieses Verhaltens bewusst und sei nicht zu überrascht, wenn dies passiert :-) (danke an @MikeGledhill für den Hinweis!)

marc_s
quelle
36
In meiner Domain musste ich pc.ValidateCredentials ("myuser", "mypassword", ContextOptions.Negotiate) angeben, sonst würde ich System.DirectoryServices.Protocols.DirectoryOperationException erhalten: Der Server kann keine Verzeichnisanforderungen verarbeiten.
Alex Peck
12
Wenn ein Kennwort abgelaufen ist oder die Konten deaktiviert sind, gibt ValidateCredentials false zurück. Leider sagt es Ihnen nicht, warum es falsch zurückgegeben wird (was schade ist, da es bedeutet, dass ich nichts Sinnvolles tun kann, wie den Benutzer umzuleiten, um sein Passwort zu ändern).
Chris J
64
Achten Sie auch auf das Gastkonto . Wenn das Gastkonto auf Domänenebene aktiviert ist, gibt ValidateCredentials true zurück, wenn Sie ihm einen nicht vorhandenen Benutzer geben. Infolgedessen möchten Sie möglicherweise anrufen, UserPrinciple.FindByIdentityum festzustellen, ob die übergebene Benutzer-ID zuerst vorhanden ist.
Chris J
7
@AlexPeck: Der Grund, warum Sie dies tun mussten (wie ich), war, dass .NET standardmäßig die folgenden Technologien verwendet: LDAP + SSL, Kerberos, dann RPC. Ich vermute, RPC ist in Ihrem Netzwerk deaktiviert (gut!) Und Kerberos wird von .NET nur verwendet, wenn Sie dies ausdrücklich mit angeben ContextOptions.Negotiate.
Brett Veenstra
5
Beachten Sie, dass dieser Code den Benutzer weiterhin mit seinem alten AD-Kennwort authentifiziert, wenn der Benutzer sein Active Directory-Kennwort ändert. Ja, wirklich. Lesen Sie hier: stackoverflow.com/questions/8949501/…
Mike Gledhill
70

Wir machen das in unserem Intranet

Sie müssen System.DirectoryServices verwenden.

Hier sind die Eingeweide des Codes

using (DirectoryEntry adsEntry = new DirectoryEntry(path, strAccountId, strPassword))
{
    using (DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry))
    {
        //adsSearcher.Filter = "(&(objectClass=user)(objectCategory=person))";
        adsSearcher.Filter = "(sAMAccountName=" + strAccountId + ")";

        try
        {
            SearchResult adsSearchResult = adsSearcher.FindOne();
            bSucceeded = true;

            strAuthenticatedBy = "Active Directory";
            strError = "User has been authenticated by Active Directory.";
        }
        catch (Exception ex)
        {
            // Failed to authenticate. Most likely it is caused by unknown user
            // id or bad strPassword.
            strError = ex.Message;
        }
        finally
        {
            adsEntry.Close();
        }
    }
}
DiningPhilanderer
quelle
9
Was setzen Sie in "Pfad"? Der Name der Domain? Der Name des Servers? Der LDAP-Pfad zur Domäne? Der LDAP-Pfad zum Server?
Ian Boyd
3
Antwort 1: Nein, wir führen es als Webdienst aus, sodass es von mehreren Stellen in der Hauptweb-App aus aufgerufen werden kann. Antwort 2: Pfad enthält LDAP-Informationen ... LDAP: // DC = Domänenname1, DC = Domänenname2, DC = com
DiningPhilanderer
3
Es scheint, dass dies eine LDAP-Injektion ermöglichen könnte. Sie können sicherstellen möchten , jede Klammer in der strAccountId zu entkommen oder entfernen
Brain2000
Bedeutet dies, dass strPasswordin LDAP im Klartext gespeichert wird?
Matt Kocaj
15
Es sollte niemals notwendig sein, Close()eine usingVariable explizit aufzurufen .
Nyerguds
62

Bei einigen hier vorgestellten Lösungen kann nicht zwischen einem falschen Benutzer / Passwort und einem Passwort unterschieden werden, das geändert werden muss. Dies kann folgendermaßen erfolgen:

using System;
using System.DirectoryServices.Protocols;
using System.Net;

namespace ProtocolTest
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                LdapConnection connection = new LdapConnection("ldap.fabrikam.com");
                NetworkCredential credential = new NetworkCredential("user", "password");
                connection.Credential = credential;
                connection.Bind();
                Console.WriteLine("logged in");
            }
            catch (LdapException lexc)
            {
                String error = lexc.ServerErrorMessage;
                Console.WriteLine(lexc);
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc);
            }
        }
    }
}

Wenn das Benutzerpasswort falsch ist oder der Benutzer nicht existiert, enthält der Fehler

"8009030C: LdapErr: DSID-0C0904DC, Kommentar: AcceptSecurityContext-Fehler, Daten 52e, v1db1",

Wenn das Benutzerkennwort geändert werden muss, enthält es

"8009030C: LdapErr: DSID-0C0904DC, Kommentar: AcceptSecurityContext-Fehler, Daten 773, v1db1"

Der lexc.ServerErrorMessageDatenwert ist eine hexadezimale Darstellung des Win32-Fehlercodes. Dies sind dieselben Fehlercodes, die beim sonstigen Aufrufen des Win32 LogonUser-API-Aufrufs zurückgegeben würden. Die folgende Liste fasst eine Reihe allgemeiner Werte mit Hex- und Dezimalwerten zusammen:

525 user not found ​(1317)
52e invalid credentials ​(1326)
530 not permitted to logon at this time (1328)
531 not permitted to logon at this workstation (1329)
532 password expired ​(1330)
533 account disabled ​(1331) 
701 account expired ​(1793)
773 user must reset password (1907)
775 user account locked (1909)
Søren Mors
quelle
2
Leider geben einige AD-Installationen den LDAP-Unterfehlercode nicht zurück, was bedeutet, dass diese Lösung nicht funktioniert.
Søren Mors
4
Vergessen Sie nicht, einige Verweise auf das Projekt hinzuzufügen: System.DirectoryServicesundSystem.DirectoryServices.Protocols
TomXP411
3
Meine Frage lautet jedoch: Wie erhalten Sie den LDAP-Servernamen? Wenn Sie eine tragbare Anwendung schreiben, können Sie nicht erwarten, dass der Benutzer die Namen der AD-Server in jedem Netzwerk kennt oder angeben muss.
TomXP411
1
Ich habe Benutzer, die sich nur an bestimmten Arbeitsstationen anmelden können. Wie gebe ich die Workstation an, für die ich die Anmeldung versuche? (Workstation1 würde mit Daten 531 ausfallen, Workstation2 würde zum Beispiel gut
funktionieren
1
Ich fühle mich komisch, weil ich nicht glaube, dass du genug Kredit bekommst. Dies ist eine vollständig verwaltete Methode ohne die Mühe eines Win32-API-Aufrufs, um festzustellen, ob "Benutzer das Kennwort zurücksetzen muss", was eindeutig keine der anderen Antworten erreicht. Gibt es eine Lücke in dieser Methode, die zu einer niedrigen Aufwertungsrate führt? hmm ...
Lionet Chen
34

sehr einfache Lösung mit DirectoryServices:

using System.DirectoryServices;

//srvr = ldap server, e.g. LDAP://domain.com
//usr = user name
//pwd = user password
public bool IsAuthenticated(string srvr, string usr, string pwd)
{
    bool authenticated = false;

    try
    {
        DirectoryEntry entry = new DirectoryEntry(srvr, usr, pwd);
        object nativeObject = entry.NativeObject;
        authenticated = true;
    }
    catch (DirectoryServicesCOMException cex)
    {
        //not authenticated; reason why is in cex
    }
    catch (Exception ex)
    {
        //not authenticated due to some other exception [this is optional]
    }

    return authenticated;
}

Der NativeObject-Zugriff ist erforderlich, um einen fehlerhaften Benutzer / ein falsches Kennwort zu erkennen

Steven A. Lowe
quelle
4
Dieser Code ist fehlerhaft, da er auch eine Berechtigungsprüfung durchführt (prüfen Sie, ob der Benutzer Active Directory-Informationen lesen darf). Der Benutzername und das Passwort können gültig sein, aber der Benutzer darf keine Informationen lesen - und eine Ausnahme erhalten. Mit anderen Worten, Sie können einen gültigen Benutzernamen und ein gültiges Passwort haben, erhalten aber dennoch eine Ausnahme.
Ian Boyd
2
Ich bin gerade dabei, nach dem nativen Äquivalent von zu fragen PrincipleContext- das nur in .NET 3.5 existiert. Aber wenn Sie .NET 3.5 oder neuer verwenden, sollten Sie verwendenPrincipleContext
Ian Boyd
28

Leider gibt es keine "einfache" Möglichkeit, die Anmeldeinformationen eines Benutzers in AD zu überprüfen.

Bei jeder bisher vorgestellten Methode wird möglicherweise ein falsch-negatives Ergebnis angezeigt: Die Creds eines Benutzers sind gültig, AD gibt jedoch unter bestimmten Umständen false zurück:

  • Der Benutzer muss das Kennwort bei der nächsten Anmeldung ändern.
  • Das Passwort des Benutzers ist abgelaufen.

In ActiveDirectory können Sie mit LDAP nicht feststellen, ob ein Kennwort ungültig ist, weil ein Benutzer das Kennwort ändern muss oder ob sein Kennwort abgelaufen ist.

Um festzustellen, ob das Kennwort geändert wurde oder das Kennwort abgelaufen ist, können Sie Win32: LogonUser () aufrufen und den Windows-Fehlercode auf die folgenden 2 Konstanten überprüfen:

  • ERROR_PASSWORD_MUST_CHANGE = 1907
  • ERROR_PASSWORD_EXPIRED = 1330
Alan
quelle
1
Darf ich fragen, woher du die Devinitionen für Expired und Must_Change hast ... Ich habe sie nur hier gefunden :)
mabstrei
Vielen Dank. Ich habe versucht herauszufinden, wie meine Validierung die ganze Zeit falsch war. Dies lag daran, dass der Benutzer sein Passwort ändern muss.
Deise Vicentin
22

Der wahrscheinlich einfachste Weg ist PInvoke LogonUser Win32 API.eg

http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html

MSDN Referenz hier ...

http://msdn.microsoft.com/en-us/library/aa378184.aspx

Ich möchte auf jeden Fall den Anmeldetyp verwenden

LOGON32_LOGON_NETWORK (3)

Dadurch wird nur ein leichtes Token erstellt - perfekt für AuthN-Prüfungen. (Andere Typen können zum Erstellen interaktiver Sitzungen usw. verwendet werden.)

stephbu
quelle
Wie @Alan hervorhebt, weist die LogonUser-API viele nützliche Merkmale auf, die über einen System.DirectoryServices-Aufruf hinausgehen.
Stephbu
3
@cciotti: Nein, das ist falsch. Die beste Möglichkeit, jemanden korrekt zu authentifizieren, besteht darin, LogonUserAPI als @ stephbu-Schreibzugriff zu verwenden. Alle anderen in diesem Beitrag beschriebenen Methoden funktionieren NICHT zu 100%. Nur eine Anmerkung, ich glaube jedoch, dass Sie einer Domain beitreten müssen, um LogonUser aufrufen zu können.
Alan
@Alan Um Anmeldeinformationen zu generieren, müssen Sie in der Lage sein, eine Verbindung zur Domain herzustellen, indem Sie ein gültiges Domain-Konto eingeben. Ich bin mir jedoch ziemlich sicher, dass Ihr Computer nicht unbedingt Mitglied der Domain sein muss.
stephbu
2
Für die LogonUserAPI muss der Benutzer das Gesetz als Teil des Betriebssystemprivilegs haben. Dies ist nicht etwas, das Benutzer erhalten - und nicht etwas, das Sie jedem Benutzer in der Organisation gewähren möchten. ( msdn.microsoft.com/en-us/library/aa378184(v=vs.85).aspx )
Ian Boyd
1
LogonUser muss laut support.microsoft.com/kb/180548 nur als Teil des Betriebssystems für Windows 2000 und darunter fungieren . Es sieht für Server 2003 und höher sauber aus.
Chris J
18

Eine vollständige .NET-Lösung besteht darin, die Klassen aus dem System.DirectoryServices-Namespace zu verwenden. Sie ermöglichen die direkte Abfrage eines AD-Servers. Hier ist ein kleines Beispiel, das dies tun würde:

using (DirectoryEntry entry = new DirectoryEntry())
{
    entry.Username = "here goes the username you want to validate";
    entry.Password = "here goes the password";

    DirectorySearcher searcher = new DirectorySearcher(entry);

    searcher.Filter = "(objectclass=user)";

    try
    {
        searcher.FindOne();
    }
    catch (COMException ex)
    {
        if (ex.ErrorCode == -2147023570)
        {
            // Login or password is incorrect
        }
    }
}

// FindOne() didn't throw, the credentials are correct

Dieser Code stellt unter Verwendung der angegebenen Anmeldeinformationen eine direkte Verbindung zum AD-Server her. Wenn die Anmeldeinformationen ungültig sind, löst searcher.FindOne () eine Ausnahme aus. Der ErrorCode entspricht dem COM-Fehler "Ungültiger Benutzername / Passwort".

Sie müssen den Code nicht als AD-Benutzer ausführen. Tatsächlich verwende ich es erfolgreich, um Informationen auf einem AD-Server von einem Client außerhalb der Domäne abzufragen!

Mathieu Garstecki
quelle
Wie wäre es mit Authentifizierungstypen? Ich denke, Sie haben es in Ihrem Code oben vergessen. :-) Standardmäßig ist DirectoryEntry.AuthenticationType auf Secured richtig eingestellt? Dieser Code funktioniert nicht auf LDAPs, die nicht gesichert sind (anonym oder keine). bin ich damit richtig?
Jerbersoft
Der Nachteil beim Abfragen eines AD-Servers besteht darin, dass Sie die Berechtigung zum Abfragen des AD-Servers haben. Ihr Berechtigungsnachweis kann gültig sein. Wenn Sie jedoch keine Berechtigung zum Abfragen von AD haben, wird der Fehler angezeigt. Deshalb wurde die sogenannte Schnellbindung geschaffen; Sie überprüfen Anmeldeinformationen, ohne die Fähigkeit des Benutzers zu autorisieren, etwas zu tun.
Ian Boyd
2
Würde dies niemandem erlauben, zu bestehen, falls eine COMException aus einem anderen Grund ausgelöst wird, bevor die Anmeldeinformationen überprüft werden?
Stefan Paul Noack
11

Noch ein .NET-Aufruf zur schnellen Authentifizierung von LDAP-Anmeldeinformationen:

using System.DirectoryServices;

using(var DE = new DirectoryEntry(path, username, password)
{
    try
    {
        DE.RefreshCache(); // This will force credentials validation
    }
    catch (COMException ex)
    {
        // Validation failed - handle how you want
    }
}
palswim
quelle
Dies ist die einzige Lösung, die bei mir funktioniert hat. Die Verwendung von PrincipalContext hat bei mir nicht funktioniert.
Daniel
PrincipalContext ist nicht gültig für eine sichere LDAP-Verbindung (auch bekannt als LDAPS, das Port 636 verwendet
Kiquenet
10

Versuchen Sie diesen Code (HINWEIS: Berichten zufolge funktioniert er unter Windows Server 2000 nicht)

#region NTLogonUser
#region Direct OS LogonUser Code
[DllImport( "advapi32.dll")]
private static extern bool LogonUser(String lpszUsername, 
    String lpszDomain, String lpszPassword, int dwLogonType, 
    int dwLogonProvider, out int phToken);

[DllImport("Kernel32.dll")]
private static extern int GetLastError();

public static bool LogOnXP(String sDomain, String sUser, String sPassword)
{
   int token1, ret;
   int attmpts = 0;

   bool LoggedOn = false;

   while (!LoggedOn && attmpts < 2)
   {
      LoggedOn= LogonUser(sUser, sDomain, sPassword, 3, 0, out token1);
      if (LoggedOn) return (true);
      else
      {
         switch (ret = GetLastError())
         {
            case (126): ; 
               if (attmpts++ > 2)
                  throw new LogonException(
                      "Specified module could not be found. error code: " + 
                      ret.ToString());
               break;

            case (1314): 
               throw new LogonException(
                  "Specified module could not be found. error code: " + 
                      ret.ToString());

            case (1326): 
               // edited out based on comment
               //  throw new LogonException(
               //   "Unknown user name or bad password.");
            return false;

            default: 
               throw new LogonException(
                  "Unexpected Logon Failure. Contact Administrator");
              }
          }
       }
   return(false);
}
#endregion Direct Logon Code
#endregion NTLogonUser

außer Sie müssen Ihre eigene benutzerdefinierte Ausnahme für "LogonException" erstellen

Charles Bretana
quelle
Verwenden Sie die Ausnahmebehandlung nicht, um Informationen von einer Methode zurückzugeben. "Unbekannter Benutzername oder falsches Passwort" ist keine Ausnahme, es ist Standardverhalten für LogonUser. Gib einfach false zurück.
Treb
Ja ... dies war ein Port aus einer alten VB6-Bibliothek ... geschrieben 2003 oder so ... (als .Net zum ersten Mal herauskam)
Charles Bretana
Unter Windows 2000 funktioniert dieser Code nicht ( support.microsoft.com/kb/180548 )
Ian Boyd
1
Das überdenken. Anmelden Das erwartete Verhalten des Benutzers besteht darin, den Benutzer anzumelden . Wenn es diese Aufgabe nicht erfüllt, es IST eine Ausnahme. Tatsächlich sollte die Methode void zurückgeben, keinen Booleschen Wert. Wenn Sie gerade einen Booleschen Wert zurückgegeben haben, kann der Benutzer der Methode den Benutzer nicht über den Grund für den Fehler informieren.
Charles Bretana
5

Wenn Sie mit .NET 2.0 und verwaltetem Code nicht weiterkommen, können Sie auf folgende Weise mit lokalen und Domänenkonten arbeiten:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Diagnostics;

static public bool Validate(string domain, string username, string password)
{
    try
    {
        Process proc = new Process();
        proc.StartInfo = new ProcessStartInfo()
        {
            FileName = "no_matter.xyz",
            CreateNoWindow = true,
            WindowStyle = ProcessWindowStyle.Hidden,
            WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
            UseShellExecute = false,
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            RedirectStandardInput = true,
            LoadUserProfile = true,
            Domain = String.IsNullOrEmpty(domain) ? "" : domain,
            UserName = username,
            Password = Credentials.ToSecureString(password)
        };
        proc.Start();
        proc.WaitForExit();
    }
    catch (System.ComponentModel.Win32Exception ex)
    {
        switch (ex.NativeErrorCode)
        {
            case 1326: return false;
            case 2: return true;
            default: throw ex;
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }

    return false;
}   
Chauwel
quelle
Funktioniert gut mit lokalen Konten der Maschine, auf der er das Skript
startet
Übrigens wird diese Methode benötigt, um dies öffentlich zu machen. Statischer SecureString ToSecureString (Zeichenfolge PwString) {char [] PasswordChars = PwString.ToCharArray (); SecureString Password = new SecureString (); foreach (char c in PasswordChars) Password.AppendChar (c); ProcessStartInfo foo = new ProcessStartInfo (); foo.Password = Passwort; return foo.Password; }
eka808
Im Gegenteil, man sollte SecureString sowieso für Passwörter verwenden. WPF PasswordBox unterstützt dies.
Stephen Drew
5

Die Windows-Authentifizierung kann aus verschiedenen Gründen fehlschlagen: einem falschen Benutzernamen oder Kennwort, einem gesperrten Konto, einem abgelaufenen Kennwort und mehr. Um zwischen diesen Fehlern zu unterscheiden, rufen Sie die LogonUser- API-Funktion über P / Invoke auf und überprüfen Sie den Fehlercode, wenn die Funktion Folgendes zurückgibt false:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

using Microsoft.Win32.SafeHandles;

public static class Win32Authentication
{
    private class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle() // called by P/Invoke
            : base(true)
        {
        }

        protected override bool ReleaseHandle()
        {
            return CloseHandle(this.handle);
        }
    }

    private enum LogonType : uint
    {
        Network = 3, // LOGON32_LOGON_NETWORK
    }

    private enum LogonProvider : uint
    {
        WinNT50 = 3, // LOGON32_PROVIDER_WINNT50
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LogonUser(
        string userName, string domain, string password,
        LogonType logonType, LogonProvider logonProvider,
        out SafeTokenHandle token);

    public static void AuthenticateUser(string userName, string password)
    {
        string domain = null;
        string[] parts = userName.Split('\\');
        if (parts.Length == 2)
        {
            domain = parts[0];
            userName = parts[1];
        }

        SafeTokenHandle token;
        if (LogonUser(userName, domain, password, LogonType.Network, LogonProvider.WinNT50, out token))
            token.Dispose();
        else
            throw new Win32Exception(); // calls Marshal.GetLastWin32Error()
    }
}

Beispielnutzung:

try
{
    Win32Authentication.AuthenticateUser("EXAMPLE\\user", "P@ssw0rd");
    // Or: Win32Authentication.AuthenticateUser("[email protected]", "P@ssw0rd");
}
catch (Win32Exception ex)
{
    switch (ex.NativeErrorCode)
    {
        case 1326: // ERROR_LOGON_FAILURE (incorrect user name or password)
            // ...
        case 1327: // ERROR_ACCOUNT_RESTRICTION
            // ...
        case 1330: // ERROR_PASSWORD_EXPIRED
            // ...
        case 1331: // ERROR_ACCOUNT_DISABLED
            // ...
        case 1907: // ERROR_PASSWORD_MUST_CHANGE
            // ...
        case 1909: // ERROR_ACCOUNT_LOCKED_OUT
            // ...
        default: // Other
            break;
    }
}

Hinweis: Für LogonUser ist eine Vertrauensbeziehung zu der Domäne erforderlich, für die Sie eine Validierung durchführen.

Michael Liu
quelle
Können Sie erklären, warum Ihre Antwort besser ist als die Antwort mit der höchsten Stimme?
Mohammad Ali
1
@MohammadAli: Wenn Sie wissen möchten, warum die Überprüfung der Anmeldeinformationen fehlgeschlagen ist (falsche Anmeldeinformationen, ein gesperrtes Konto, ein abgelaufenes Kennwort usw.), werden Sie von der LogonUser-API-Funktion darüber informiert. Im Gegensatz dazu wird die PrincipalContext.ValidateCredentials-Methode (gemäß Kommentaren zur Antwort von marc_s) dies nicht tun. In all diesen Fällen wird false zurückgegeben. Auf der anderen Seite erfordert LogonUser eine Vertrauensbeziehung mit der Domäne, PrincipalContext.ValidateCredentials (glaube ich) jedoch nicht.
Michael Liu
2

Meine einfache Funktion

 private bool IsValidActiveDirectoryUser(string activeDirectoryServerDomain, string username, string password)
    {
        try
        {
            DirectoryEntry de = new DirectoryEntry("LDAP://" + activeDirectoryServerDomain, username + "@" + activeDirectoryServerDomain, password, AuthenticationTypes.Secure);
            DirectorySearcher ds = new DirectorySearcher(de);
            ds.FindOne();
            return true;
        }
        catch //(Exception ex)
        {
            return false;
        }
    }
Hossein Andarkhora
quelle
1

Hier meine komplette Authentifizierungslösung als Referenz.

Fügen Sie zunächst die folgenden vier Referenzen hinzu

 using System.DirectoryServices;
 using System.DirectoryServices.Protocols;
 using System.DirectoryServices.AccountManagement;
 using System.Net; 

private void AuthUser() { 


      try{
            string Uid = "USER_NAME";
            string Pass = "PASSWORD";
            if (Uid == "")
            {
                MessageBox.Show("Username cannot be null");
            }
            else if (Pass == "")
            {
                MessageBox.Show("Password cannot be null");
            }
            else
            {
                LdapConnection connection = new LdapConnection("YOUR DOMAIN");
                NetworkCredential credential = new NetworkCredential(Uid, Pass);
                connection.Credential = credential;
                connection.Bind();

                // after authenticate Loading user details to data table
                PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
                UserPrincipal user = UserPrincipal.FindByIdentity(ctx, Uid);
                DirectoryEntry up_User = (DirectoryEntry)user.GetUnderlyingObject();
                DirectorySearcher deSearch = new DirectorySearcher(up_User);
                SearchResultCollection results = deSearch.FindAll();
                ResultPropertyCollection rpc = results[0].Properties;
                DataTable dt = new DataTable();
                DataRow toInsert = dt.NewRow();
                dt.Rows.InsertAt(toInsert, 0);

                foreach (string rp in rpc.PropertyNames)
                {
                    if (rpc[rp][0].ToString() != "System.Byte[]")
                    {
                        dt.Columns.Add(rp.ToString(), typeof(System.String));

                        foreach (DataRow row in dt.Rows)
                        {
                            row[rp.ToString()] = rpc[rp][0].ToString();
                        }

                    }  
                }
             //You can load data to grid view and see for reference only
                 dataGridView1.DataSource = dt;


            }
        } //Error Handling part
        catch (LdapException lexc)
        {
            String error = lexc.ServerErrorMessage;
            string pp = error.Substring(76, 4);
            string ppp = pp.Trim();

            if ("52e" == ppp)
            {
                MessageBox.Show("Invalid Username or password, contact ADA Team");
            }
            if ("775​" == ppp)
            {
                MessageBox.Show("User account locked, contact ADA Team");
            }
            if ("525​" == ppp)
            {
                MessageBox.Show("User not found, contact ADA Team");
            }
            if ("530" == ppp)
            {
                MessageBox.Show("Not permitted to logon at this time, contact ADA Team");
            }
            if ("531" == ppp)
            {
                MessageBox.Show("Not permitted to logon at this workstation, contact ADA Team");
            }
            if ("532" == ppp)
            {
                MessageBox.Show("Password expired, contact ADA Team");
            }
            if ("533​" == ppp)
            {
                MessageBox.Show("Account disabled, contact ADA Team");
            }
            if ("533​" == ppp)
            {
                MessageBox.Show("Account disabled, contact ADA Team");
            }



        } //common error handling
        catch (Exception exc)
        {
            MessageBox.Show("Invalid Username or password, contact ADA Team");

        }

        finally {
            tbUID.Text = "";
            tbPass.Text = "";

        }
    }
Gayan Chinthaka Dharmarathna
quelle