Authentifizieren mit Active Directory mit Java unter Linux

Ich habe eine einfache Aufgabe der Authentifizierung gegen Active Directory mit Java. Nur Anmeldeinformationen überprüfen und sonst nichts. Nehmen wir an, meine Domain ist “fun.xyz.tld”, der OU-Pfad ist unbekannt und der Benutzername / das Passwort ist testu / testp.

Ich weiß, dass es einige Java-Bibliotheken gibt, die diese Aufgabe vereinfachen, aber ich konnte sie nicht implementieren. Die meisten Beispiele, die ich gefunden habe, adressieren LDAP im Allgemeinen, nicht speziell Active Directory. Das Ausstellen einer LDAP-Anfrage bedeutet, dass darin ein OU-Pfad gesendet wird, den ich nicht habe. Außerdem sollte die Anwendung, die die LDAP-Anfrage absetzt, bereits an Active Directory gebunden sein, um darauf zugreifen zu können … Unsicher, da die Zugangsdaten irgendwo auffindbar gespeichert werden müssten. Ich würde gerne eine Testbindung mit Test-Credentials, wenn möglich – das würde bedeuten, dass das Konto gültig ist.

Und wenn möglich, gibt es eine Möglichkeit, einen solchen Authentifizierungsmechanismus zu verschlüsseln? Ich weiß, dass AD Kerberos verwendet, aber nicht sicher, ob Javas LDAP-Methoden dies tun.

Hat jemand ein Beispiel für Arbeitscode? Vielen Dank.

   

    Es gibt 3 Authentifizierungsprotokolle, die zur Authentifizierung zwischen Java und Active Directory unter Linux oder einer anderen Plattform verwendet werden können (und diese sind nicht nur für HTTP-Dienste spezifisch):

    1. Kerberos – Kerberos bietet Single Sign-On (SSO) und Delegation, aber Webserver benötigen auch SPNEGO-Unterstützung, um SSO über IE zu akzeptieren.

    2. NTLM – NTLM unterstützt SSO über IE (und andere Browser, wenn sie ordnungsgemäß konfiguriert sind).

    3. LDAP – Eine LDAP-Bindung kann verwendet werden, um einen Kontonamen und ein Passwort einfach zu validieren.

    Es gibt auch etwas namens “ADFS”, das SSO für Websites bereitstellt, die SAML verwenden, das in den Windows SSP aufruft. In der Praxis handelt es sich also im Wesentlichen um einen Umweg über eines der anderen oben genannten Protokolle.

    Jedes Protokoll hat seine Vorteile, aber als Faustregel sollte man im Allgemeinen versuchen, “so zu machen, wie Windows es tut”. Was macht Windows?

    Erstens favorisiert die Authentifizierung zwischen zwei Windows-Maschinen Kerberos, weil Server nicht mit dem Domänencontroller kommunizieren müssen und Clients Kerberos-Tickets zwischenspeichern können, was die Belastung der Domänencontroller verringert (und weil Kerberos die Delegierung unterstützt).

    Wenn jedoch die authentifizierenden Parteien nicht über Domänenkonten verfügen oder wenn der Client nicht mit dem Domänencontroller kommunizieren kann, ist NTLM erforderlich. Daher schließen sich Kerberos und NTLM nicht gegenseitig aus und NTLM wird nicht von Kerberos veraltet. Tatsächlich ist NTLM in mancher Hinsicht besser als Kerberos. Beachten Sie, dass wenn ich Kerberos und NTLM im selben Atemzug erwähne, auch SPENGO und Integrated Windows Authentication (IWA) erwähnen muss. IWA ist ein einfacher Begriff, der im Wesentlichen Kerberos oder NTLM oder SPNEGO zum Aushandeln von Kerberos oder NTLM bedeutet.

    Die Verwendung einer LDAP-Bindung zur validation von Anmeldeinformationen ist nicht effizient und erfordert SSL. Aber bis vor kurzem die Implementierung von Kerberos und NTLM war schwierig, so dass die Verwendung von LDAP als Make-Shift-Authentifizierungsdienst beibehalten hat. Aber an dieser Stelle sollte es im Allgemeinen vermieden werden. LDAP ist ein Verzeichnis von Informationen und kein Authentifizierungsdienst. Verwenden Sie es für den beabsichtigten Zweck.

    Wie implementieren Sie Kerberos oder NTLM in Java und insbesondere im Kontext von Webanwendungen?

    Es gibt eine Reihe großer Unternehmen wie Quest Software und Centrify, die Lösungen speziell für Java anbieten. Ich kann diese nicht wirklich kommentieren, da es sich um unternehmensweite “Identitätsmanagement-Lösungen” handelt. Aus dem Blick auf den Marketing-Spin auf ihrer Website ist es schwer zu sagen, welche Protokolle genau verwendet werden und wie. Sie müssen sie für die Details kontaktieren.

    Die Implementierung von Kerberos in Java ist nicht besonders schwierig, da die Standard-Java-Bibliotheken Kerberos über die org.ietf.gssapi-classn unterstützen. Bis vor kurzem gab es jedoch eine große Hürde – IE sendet keine rohen Kerberos-Tokens, sondern sendet SPNEGO-Token. Aber mit Java 6 wurde SPNEGO implementiert. Theoretisch sollten Sie in der Lage sein, einen GSSAPI-Code zu schreiben, der IE-Clients authentifizieren kann. Aber ich habe es nicht versucht. Die Sun-Implementierung von Kerberos war im Laufe der Jahre eine Komödie von Fehlern. Aufgrund der Erfolgsbilanz von Sun in diesem Bereich würde ich keine Versprechen über die Implementierung von SPENGO abgeben, bis Sie diesen Vogel in der Hand haben.

    Für NTLM gibt es ein freies OSS-Projekt namens JCIFS mit einem HTTP-Authentifizierungs-Servlet-Filter für NTLM. Es verwendet jedoch eine Man-in-the-Middle-Methode, um die Anmeldeinformationen mit einem SMB-Server zu überprüfen, der nicht mit NTLMv2 funktioniert (was langsam zu einer erforderlichen Domänensicherheitsrichtlinie wird). Aus diesem Grund und anderen wird der HTTP-Filter-Teil von JCIFS entfernt. Beachten Sie, dass es mehrere Spin-offs gibt, die JCIFS verwenden, um dieselbe Technik zu implementieren. Wenn Sie also andere Projekte sehen, die behaupten, NTLM SSO zu unterstützen, überprüfen Sie das Kleingedruckte.

    Die einzige Möglichkeit, NTLM-Anmeldeinformationen mit Active Directory zu validieren, besteht darin, den DCERPC-Aufruf NetrLogonSamLogon über NETLOGON mit Secure Channel zu verwenden. Gibt es so etwas in Java? Ja. Hier ist es:

    http://www.ioplex.com/jespa.html

    Jespa ist eine 100% Java NTLM-Implementierung, die NTLMv2, NTLMv1, vollständige Integritäts- und Vertraulichkeitsoptionen sowie die oben genannte validation von NETLOGON-Anmeldeinformationen unterstützt. Dazu gehören ein HTTP-SSO-Filter, ein JAAS LoginModule, ein HTTP-Client, ein SASL-Client und -Server (mit JNDI-Bindung), ein generischer “Sicherheitsanbieter” zum Erstellen benutzerdefinierter NTLM-Dienste und mehr.

    Mike

    Hier ist der Code, den ich anhand eines Beispiels aus diesem Blog zusammengestellt habe: LINK und diese Quelle: LINK .

    import com.sun.jndi.ldap.LdapCtxFactory; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Iterator; import javax.naming.Context; import javax.naming.AuthenticationException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import static javax.naming.directory.SearchControls.SUBTREE_SCOPE; class App2 { public static void main(String[] args) { if (args.length != 4 && args.length != 2) { System.out.println("Purpose: authenticate user against Active Directory and list group membership."); System.out.println("Usage: App2    "); System.out.println("Short usage: App2  "); System.out.println("(short usage assumes 'xyz.tld' as domain and 'abc' as server)"); System.exit(1); } String domainName; String serverName; if (args.length == 4) { domainName = args[2]; serverName = args[3]; } else { domainName = "xyz.tld"; serverName = "abc"; } String username = args[0]; String password = args[1]; System.out .println("Authenticating " + username + "@" + domainName + " through " + serverName + "." + domainName); // bind by using the specified username/password Hashtable props = new Hashtable(); String principalName = username + "@" + domainName; props.put(Context.SECURITY_PRINCIPAL, principalName); props.put(Context.SECURITY_CREDENTIALS, password); DirContext context; try { context = LdapCtxFactory.getLdapCtxInstance("ldap://" + serverName + "." + domainName + '/', props); System.out.println("Authentication succeeded!"); // locate this user's record SearchControls controls = new SearchControls(); controls.setSearchScope(SUBTREE_SCOPE); NamingEnumeration renum = context.search(toDC(domainName), "(& (userPrincipalName=" + principalName + ")(objectClass=user))", controls); if (!renum.hasMore()) { System.out.println("Cannot locate user information for " + username); System.exit(1); } SearchResult result = renum.next(); List groups = new ArrayList(); Attribute memberOf = result.getAttributes().get("memberOf"); if (memberOf != null) {// null if this user belongs to no group at all for (int i = 0; i < memberOf.size(); i++) { Attributes atts = context.getAttributes(memberOf.get(i).toString(), new String[] { "CN" }); Attribute att = atts.get("CN"); groups.add(att.get().toString()); } } context.close(); System.out.println(); System.out.println("User belongs to: "); Iterator ig = groups.iterator(); while (ig.hasNext()) { System.out.println(" " + ig.next()); } } catch (AuthenticationException a) { System.out.println("Authentication failed: " + a); System.exit(1); } catch (NamingException e) { System.out.println("Failed to bind to LDAP / get account information: " + e); System.exit(1); } } private static String toDC(String domainName) { StringBuilder buf = new StringBuilder(); for (String token : domainName.split("\\.")) { if (token.length() == 0) continue; // defensive check if (buf.length() > 0) buf.append(","); buf.append("DC=").append(token); } return buf.toString(); } } 

    Ich habe gerade ein Projekt abgeschlossen, das AD und Java verwendet. Wir haben Spring ldapTemplate verwendet.

    AD ist LDAP-konform (fast), ich glaube nicht, dass Sie Probleme mit Ihrer Aufgabe haben werden. Ich meine die Tatsache, dass es sich um AD oder einen anderen LDAP-Server handelt, egal, ob Sie nur eine Verbindung herstellen möchten.

    Ich würde mir folgendes ansehen: Spring LDAP

    Sie haben auch Beispiele.

    Wie bei der Verschlüsselung verwendeten wir SSL-Verbindung (also war es LDAPS). AD musste auf einem SSL-Port / Protokoll konfiguriert werden.

    Stellen Sie zunächst sicher, dass Sie über eine LDAP-IDE eine Verbindung zu Ihrem AD herstellen können. Ich benutze Apache Directory Studio , es ist wirklich cool, und es ist in Java geschrieben. Das ist alles was ich brauchte. Zu Testzwecken können Sie auch Apache Directory Server installieren

    Wie ioplex und andere gesagt haben, gibt es viele Möglichkeiten. Zur Authentifizierung mit LDAP (und der Novell LDAP API) habe ich Folgendes verwendet:

     LDAPConnection connection = new LDAPConnection( new LDAPJSSEStartTLSFactory() ); connection.connect(hostname, port); connection.startTLS(); connection.bind(LDAPConnection.LDAP_V3, username+"@"+domain, password.getBytes()); 

    Als “besonderes Feature” erlaubt Active Directory die Bindung von LDAP an “user @ domain”, ohne den definierten Namen des Accounts zu verwenden. Dieser Code verwendet StartTLS, um die TLS-Verschlüsselung für die Verbindung zu aktivieren. Die andere Alternative ist LDAP über SSL, das von meinen AD-Servern nicht unterstützt wird.

    Der wahre Trick besteht darin, den Server und den Host zu finden. Der offizielle Weg besteht darin, einen DNS SRV (Service) Record Lookup zu verwenden, um ein Bündel von möglichen Hosts zu finden, und dann einen UDP-basierten LDAP “Ping” (in einem bestimmten Microsoft Format) auszuführen, um den richtigen Server zu finden. Wenn Sie interessiert sind, habe ich einige Blogartikel über meine Reise von Abenteuer und Entdeckung in diesem Bereich veröffentlicht.

    Wenn Sie Kerberos-basierte Benutzername / Passwort-Authentifizierung durchführen möchten, betrachten Sie einen anderen Kessel Fisch; Es ist mit dem Java-GSS-API-Code machbar, obwohl ich nicht sicher bin, ob es den letzten Schritt zur validation der Authentifizierung durchführt. (Der Code, der die validation durchführt, kann den AD-Server kontaktieren, um den Benutzernamen und das Kennwort zu überprüfen. Dies führt zu einem Ticket-Erteilungsticket für den Benutzer. Um sicherzustellen, dass der AD-Server nicht imitiert wird, muss er auch versuchen, ein Ticket zu erhalten der Benutzer an sich selbst, was etwas komplizierter ist.)

    Wenn Sie Kerberos-basiertes Single Sign-On durchführen möchten, vorausgesetzt, dass Ihre Benutzer bei der Domäne authentifiziert sind, können Sie dies auch mit dem Java-GSS-API-Code tun. Ich würde ein Codebeispiel posten, aber ich muss meinen abscheulichen Prototyp noch in etwas verwandeln, das für menschliche Augen geeignet ist. Einige Informationen zu SpringSource finden Sie hier .

    Wenn Sie nach NTLM suchen (was ich zu verstehen gegeben habe, ist weniger sicher) oder etwas anderes, nun, viel Glück.

    Werden nur Anmeldeinformationen überprüft? In diesem Fall könnten Sie einfach nur kerberos und sich nicht mit LDAP .

    Wenn Sie nur mit Kerberos gegen AD authentifizieren möchten, sollte ein einfaches Programm http://spnego.sourceforge.net/HelloKDC.java dies tun.

    Werfen Sie einen Blick auf die “Pre-Flight” -Dokumentation des Projekts, die über das Programm HelloKDC.java spricht.

    ldap-Authentifizierung ohne SSL ist nicht sicher und jeder kann Benutzeranmeldeinformationen anzeigen, da ldap client usernamae und das Passwort während des ldap-Bindevorgangs überträgt. Also immer ldaps-Protokoll verwenden. Quelle: Ldap-Authentifizierung Aktives Verzeichnis in Java Spring Security mit Beispiel

    Ich empfehle Ihnen, sich das Adbroker-Paket des oVirt- Projekts anzusehen . Es verwendet Spring-Ldap und das Krb5 JAAS Login-Modul (mit GSSAPI), um sich mit Kerberos gegen Ldap-Server (Active-Directory, ipa, rhds, Tivoli-DS) zu authentifizieren. Suchen Sie nach dem Code unter engine \ backend \ manager \ modules \ bll \ src \ main \ java \ org \ ouvirt \ engine \ core \ bll \ adbroker

    Sie können git verwenden, um das Repository zu klonen oder den gerrit- Link zu verwenden