Es gibt drei Authentifizierungsprotokolle, mit denen die Authentifizierung zwischen Java und Active Directory unter Linux oder einer anderen Plattform durchgeführt werden kann (und die nicht nur für HTTP-Dienste spezifisch sind):
Kerberos - Kerberos bietet Single Sign-On (SSO) und Delegierung, aber Webserver benötigen auch SPNEGO-Unterstützung, um SSO über den IE zu akzeptieren.
NTLM - NTLM unterstützt SSO über den Internet Explorer (und andere Browser, wenn diese ordnungsgemäß konfiguriert sind).
LDAP - Eine LDAP-Bindung kann verwendet werden, um einfach einen Kontonamen und ein Kennwort zu überprüfen.
Es gibt auch etwas namens "ADFS", das SSO für Websites mit SAML bereitstellt, die den Windows-SSP aufrufen. In der Praxis handelt es sich also im Grunde genommen um einen Umweg, eines der anderen oben genannten Protokolle zu verwenden.
Jedes Protokoll hat seine Vorteile, aber als Faustregel sollten Sie für maximale Kompatibilität im Allgemeinen versuchen, "so zu tun, wie Windows es tut". Was macht Windows?
Erstens begünstigt die Authentifizierung zwischen zwei Windows-Computern Kerberos, da Server nicht mit dem Domänencontroller kommunizieren müssen und Clients Kerberos-Tickets zwischenspeichern können, wodurch die Belastung der Domänencontroller verringert wird (und weil Kerberos die Delegierung unterstützt).
Wenn die authentifizierenden Parteien jedoch nicht beide über Domänenkonten verfügen oder der Client nicht mit dem DC kommunizieren kann, ist NTLM erforderlich. Kerberos und NTLM schließen sich also nicht gegenseitig aus und NTLM wird von Kerberos nicht überholt. In gewisser Hinsicht ist NTLM sogar besser als Kerberos. Beachten Sie, dass ich, wenn ich Kerberos und NTLM in einem Atemzug erwähne, auch SPENGO und die integrierte Windows-Authentifizierung (IWA) erwähnen muss. IWA ist ein einfacher Begriff, der im Grunde Kerberos oder NTLM oder SPNEGO bedeutet, um Kerberos oder NTLM auszuhandeln.
Die Verwendung einer LDAP-Bindung zum Überprüfen von Anmeldeinformationen ist nicht effizient und erfordert SSL. Bis vor kurzem war die Implementierung von Kerberos und NTLM jedoch schwierig, sodass die Verwendung von LDAP als Make-Shift-Authentifizierungsdienst weiterhin besteht. An dieser Stelle sollte dies jedoch generell vermieden werden. LDAP ist ein Informationsverzeichnis und kein Authentifizierungsdienst. Verwenden Sie es für den vorgesehenen 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 anbieten, die speziell Java erwähnen. Ich kann diese nicht wirklich kommentieren, da es sich um unternehmensweite "Identity Management-Lösungen" handelt. Wenn man sich also den Marketing-Spin auf ihrer Website ansieht, ist es schwierig, genau zu sagen, welche Protokolle wie verwendet werden. Sie müssten sie für die Details kontaktieren.
Die Implementierung von Kerberos in Java ist nicht besonders schwierig, da die Standard-Java-Bibliotheken Kerberos über die Klassen org.ietf.gssapi unterstützen. Bis vor kurzem gab es jedoch eine große Hürde: Der IE sendet keine rohen Kerberos-Token, sondern SPNEGO-Token. Aber mit Java 6 wurde SPNEGO implementiert. Theoretisch sollten Sie in der Lage sein, GSSAPI-Code zu schreiben, mit dem IE-Clients authentifiziert werden können. 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 Zusagen über die SPENGO-Implementierung machen, bis Sie diesen Vogel in der Hand haben.
Für NTLM gibt es ein kostenloses OSS-Projekt namens JCIFS mit einem Servlet-Filter für die NTLM-HTTP-Authentifizierung. Es wird jedoch eine Man-in-the-Middle-Methode verwendet, um die Anmeldeinformationen mit einem SMB-Server zu überprüfen, der nicht mit NTLMv2 funktioniert (was langsam zu einer erforderlichen Sicherheitsrichtlinie für Domänen wird). Aus diesem und anderen Gründen soll der HTTP-Filterteil von JCIFS entfernt werden. Beachten Sie, dass es eine Reihe von Ausgründungen 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 einzig richtige Möglichkeit, NTLM-Anmeldeinformationen mit Active Directory zu überprüfen, ist die Verwendung des DCERPC-Aufrufs NetrLogonSamLogon über NETLOGON mit Secure Channel. 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 erwähnte Überprüfung der NETLOGON-Anmeldeinformationen unterstützt. Dazu gehören ein HTTP-SSO-Filter, ein JAAS-Anmeldemodul, ein HTTP-Client, ein SASL-Client und -Server (mit JNDI-Bindung), ein generischer "Sicherheitsanbieter" zum Erstellen benutzerdefinierter NTLM-Dienste und vieles 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 <username> <password> <domain> <server>"); System.out.println("Short usage: App2 <username> <password>"); 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<SearchResult> 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<String> groups = new ArrayList<String>(); 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(); } }
quelle
import com.sun.jndi.ldap.LdapCtxFactory;
- this will most likely only work with a Sun JVM.I just finished a project that uses AD and Java. We used Spring ldapTemplate.
AD is LDAP compliant (almost), I don't think you will have any issues with the task you have. I mean the fact that it is AD or any other LDAP server it doesn't matter if you want just to connect.
I would take a look at: Spring LDAP
They have examples too.
As for encryption, we used SSL connection (so it was LDAPS). AD had to be configured on a SSL port/protocol.
But first of all, make sure you can properly connect to your AD via an LDAP IDE. I use Apache Directory Studio, it is really cool, and it is written in Java. That is all I needed. For testing purposes you could also install Apache Directory Server
quelle
As ioplex and others have said, there are many options. To authenticate using LDAP (and the Novell LDAP API), I have used something like:
LDAPConnection connection = new LDAPConnection( new LDAPJSSEStartTLSFactory() ); connection.connect(hostname, port); connection.startTLS(); connection.bind(LDAPConnection.LDAP_V3, username+"@"+domain, password.getBytes());
As a "special feature", Active Directory allows LDAP binds against "user@domain" without using the distinguished name of the account. This code uses StartTLS to enable TLS encryption on the connection; the other alternative is LDAP over SSL, which is not supported by my AD servers.
The real trick is in locating the server and host; the official way is to use a DNS SRV (service) record lookup to locate a bundle of candidate hosts, then do a UDP-based LDAP "ping" (in a particular Microsoft format) to locate the correct server. If you are interested, I've posted some blog articles about my journey of adventure and discovery in that area.
If you want to do Kerberos-based username/password authentication, you are looking at another kettle of fish; it is doable with the Java GSS-API code, although I am not sure it performs the final step to validate the authentication. (The code doing the validation can contact the AD server to check the username and password, which results in a ticket granting ticket for the user, but to ensure the AD server is not being impersonated, it also needs to try to get a ticket for the user to itself, which is somewhat more complicated.)
If you want to do Kerberos-based single sign-on, assuming your users are authenticated to the domain, you can do that as well with the Java GSS-API code. I would post a code sample, but I still need to turn my hideous prototype into something fit for human eyes. Check out some code from SpringSource for some inspiration.
If you are looking for NTLM (which I was given to understand is less secure) or something else, well, good luck.
quelle
Are you just verifying credentials? In that case you could just do plain
kerberos
and not bother withLDAP
.quelle
If all you want to do is authenticate against AD using Kerberos, then a simple http://spnego.sourceforge.net/HelloKDC.java program should do it.
Take a look at the project's "pre-flight" documentation which talks about the HelloKDC.java program.
quelle
http://java.sun.com/docs/books/tutorial/jndi/ldap/auth_mechs.html
SASL mechanism supports Kerberos v4 and v5. http://java.sun.com/docs/books/tutorial/jndi/ldap/sasl.html
quelle
ldap authentication without SSL is not safe and anyone can view user credential because ldap client transfer usernamae and password during ldap bind operation So Always use ldaps protocol. source: Ldap authentication Active directory in Java Spring Security with Example
quelle
I recommend you to look at the adbroker package of the oVirt project. It uses Spring-Ldap and the Krb5 JAAS Login module (with GSSAPI) in order to authenticate using Kerberos against Ldap servers (Active-Directory, ipa, rhds, Tivoli-DS). Look for the code at engine\backend\manager\modules\bll\src\main\java\org\ovirt\engine\core\bll\adbroker
You can use git to clone the repository or browse using the gerrit link
quelle