Autenticazione contro Active Directory con Java su Linux

Ho una semplice attività di autenticazione con Active Directory utilizzando Java. Solo verificando le credenziali e nient’altro. Diciamo che il mio dominio è “fun.xyz.tld”, il percorso OU è sconosciuto e username / password è testu / testp.

So che ci sono alcune librerie Java là fuori che semplificano questo compito, ma non ho avuto successo nell’attuarle. La maggior parte degli esempi che ho trovato hanno affrontato LDAP in generale, non specificamente Active Directory. L’emissione della richiesta LDAP implica l’invio di un percorso OU in esso, che non ho. Inoltre, l’applicazione che invia la richiesta LDAP deve essere già associata ad Active Directory per accedervi … Non sicuro, poiché le credenziali dovrebbero essere memorizzate in qualche posto rilevabile. Vorrei un test di associazione con credenziali di test, se ansible – questo significherebbe che l’account è valido.

Infine, se ansible, esiste un modo per rendere crittografato tale meccanismo di autenticazione? So che AD utilizza Kerberos, ma non sono sicuro se i metodi LDAP di Java lo fanno.

Qualcuno ha un esempio di codice funzionante? Grazie.

Esistono 3 protocolli di autenticazione che possono essere utilizzati per eseguire l’autenticazione tra Java e Active Directory su Linux o qualsiasi altra piattaforma (e questi non sono solo specifici per i servizi HTTP):

  1. Kerberos – Kerberos fornisce Single Sign-On (SSO) e delega ma i server Web hanno anche bisogno del supporto SPNEGO per accettare SSO tramite IE.

  2. NTLM – NTLM supporta SSO tramite IE (e altri browser se sono configurati correttamente).

  3. LDAP: è ansible utilizzare un binding LDAP per semplicemente convalidare un nome account e una password.

C’è anche qualcosa chiamato “ADFS” che fornisce SSO per i siti web che utilizzano SAML che chiama nell’SPS di Windows, quindi in pratica è fondamentalmente un modo indiretto di utilizzare uno degli altri protocolli precedenti.

Ogni protocollo ha i suoi vantaggi ma, come regola generale, per la massima compatibilità dovresti generalmente provare a “fare come fa Windows”. Quindi cosa fa Windows?

Innanzitutto, l’autenticazione tra due macchine Windows privilegia Kerberos perché i server non hanno bisogno di comunicare con il controller di dominio ei client possono memorizzare nella cache i ticket Kerberos che riducono il carico sui controller di dominio (e perché Kerberos supporta la delega).

Ma se le parti autenticanti non hanno entrambi account di dominio o se il client non può comunicare con il controller di dominio, è necessario NTLM. Quindi Kerberos e NTLM non si escludono a vicenda e NTLM non è obsoleto da Kerberos. In effetti in qualche modo NTLM è migliore di Kerberos. Si noti che quando si parla di Kerberos e NTLM nello stesso respiro devo menzionare SPENGO e Integrated Windows Authentication (IWA). IWA è un termine semplice che significa fondamentalmente Kerberos o NTLM o SPNEGO per negoziare Kerberos o NTLM.

L’utilizzo di un binding LDAP come metodo per convalidare le credenziali non è efficiente e richiede SSL. Ma fino a poco tempo fa l’implementazione di Kerberos e NTLM si è rivelata difficile, quindi l’utilizzo di LDAP come un servizio di autenticazione make-shift è persistito. Ma a questo punto dovrebbe essere generalmente evitato. LDAP è una directory di informazioni e non un servizio di autenticazione. Usalo per il suo scopo.

Quindi, come si implementa Kerberos o NTLM in Java e nel contesto delle applicazioni Web in particolare?

Ci sono un certo numero di grandi aziende come Quest Software e Centrify che hanno soluzioni che menzionano specificamente Java. Non posso davvero commentare queste cose perché sono “soluzioni di gestione delle id quadro” a livello aziendale, quindi, dal guardare il giro del marketing sul loro sito web, è difficile dire esattamente quali protocolli vengono utilizzati e come. Avresti bisogno di contattarli per i dettagli.

Implementare Kerberos in Java non è terribilmente difficile in quanto le librerie Java standard supportano Kerberos attraverso le classi org.ietf.gssapi. Tuttavia, fino a poco tempo fa c’è stato un grosso ostacolo: IE non invia token Kerberos non elaborati, ma invia token SPNEGO. Ma con Java 6, SPNEGO è stato implementato. In teoria dovresti essere in grado di scrivere un codice GSSAPI in grado di autenticare i client IE. Ma non l’ho provato L’implementazione di Sun Kerberos è stata una commedia di errori nel corso degli anni, quindi, sulla base dei precedenti di Sun in questo settore, non avrei promesso nulla sulla loro implementazione di SPENGO fino a quando non avrai questo uccello in mano.

Per NTLM, esiste un progetto OSS gratuito denominato JCIFS con filtro Servlet di autenticazione HTTP NTLM. Tuttavia utilizza un metodo man-in-the-middle per convalidare le credenziali con un server SMB che non funziona con NTLMv2 (che sta lentamente diventando un criterio di sicurezza del dominio richiesto). Per questo motivo e altri, è prevista la rimozione della parte HTTP Filter di JCIFS. Nota che ci sono un numero di spin-off che usano JCIFS per implementare la stessa tecnica. Quindi, se vedi altri progetti che sostengono di supportare NTLM SSO, controlla la stampa fine.

L’unico modo corretto per convalidare le credenziali NTLM con Active Directory consiste nell’utilizzare la chiamata DCERPC NetrLogonSamLogon su NETLOGON con Secure Channel. Esiste una cosa simile in Java? Sì. Ecco qui:

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

Jespa è un’implementazione 100% Java NTLM che supporta NTLMv2, NTLMv1, opzioni complete di integrità e riservatezza e la suddetta convalida delle credenziali NETLOGON. Include un filtro SSO HTTP, un modulo di accesso JAAS, un client HTTP, un client SASL e un server (con binding JNDI), un “provider di sicurezza” generico per la creazione di servizi NTLM personalizzati e altro ancora.

Mike

Ecco il codice che ho creato in base all’esempio di questo blog: LINK e questa fonte: 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(); } } 

Ho appena finito un progetto che usa AD e Java. Abbiamo usato Spring ldapTemplate.

AD è conforms a LDAP (quasi), non penso che avrai problemi con l’attività che hai. Intendo il fatto che sia AD o qualsiasi altro server LDAP non importa se vuoi solo connetterti.

Darei un’occhiata a: Spring LDAP

Hanno anche esempi.

Per quanto riguarda la crittografia, abbiamo usato la connessione SSL (quindi era LDAPS). AD doveva essere configurato su una porta / protocollo SSL.

Ma prima di tutto, assicurati di poterti colbind correttamente al tuo annuncio tramite un IDE LDAP. Io uso Apache Directory Studio , è davvero interessante, ed è scritto in Java. Questo è tutto ciò di cui avevo bisogno. A scopo di test, è ansible installare anche Apache Directory Server

Come hanno detto ioplex e altri, ci sono molte opzioni. Per autenticare usando LDAP (e l’API LDAP Novell), ho usato qualcosa del tipo:

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

Come “caratteristica speciale”, Active Directory consente il binding LDAP contro “utente @ dominio” senza utilizzare il nome distinto dell’account. Questo codice utilizza StartTLS per abilitare la crittografia TLS sulla connessione; l’altra alternativa è LDAP su SSL, che non è supportato dai miei server AD.

Il vero trucco sta nel localizzare il server e l’host; il modo ufficiale è utilizzare una ricerca record DNS SRV (servizio) per individuare un fascio di host candidati, quindi eseguire un ping “LDAP” basato su UDP (in un particolare formato Microsoft) per individuare il server corretto. Se sei interessato, ho pubblicato alcuni articoli sul mio viaggio di avventura e scoperta in quell’area.

Se si desidera eseguire l’autenticazione nome utente / password basata su Kerberos, si sta guardando un altro bollitore di pesce; è fattibile con il codice Java GSS-API, anche se non sono sicuro che compia il passo finale per convalidare l’autenticazione. (Il codice che esegue la convalida può contattare il server AD per verificare il nome utente e la password, il che comporta un ticket di concessione ticket per l’utente, ma per assicurarsi che il server AD non venga rappresentato, è necessario provare a ottenere un ticket per l’utente a se stesso, che è un po ‘più complicato.)

Se si desidera eseguire il single sign-on basato su Kerberos, supponendo che gli utenti siano autenticati nel dominio, è ansible farlo anche con il codice Java GSS-API. Pubblicheremmo un esempio di codice, ma ho ancora bisogno di trasformare il mio odioso prototipo in qualcosa di adatto per gli occhi umani. Controlla qualche codice da SpringSource per qualche ispirazione.

Se stai cercando NTLM (che mi è stato dato per capire è meno sicuro) o qualcos’altro, beh, buona fortuna.

Stai solo verificando le credenziali? In tal caso potresti semplicemente fare kerberos e non preoccuparti di LDAP .

Se tutto ciò che si vuole fare è autenticarsi con AD usando Kerberos, allora un semplice programma http://spnego.sourceforge.net/HelloKDC.java dovrebbe farlo.

Dai un’occhiata alla documentazione “pre-volo” del progetto che parla del programma HelloKDC.java.

l’autenticazione ldap senza SSL non è sicura e chiunque può visualizzare le credenziali dell’utente perché il client ldap trasferisce usernamae e password durante l’operazione di collegamento LDAP Quindi utilizzare sempre il protocollo LDAP. origine: autenticazione LDAP Directory triggers in Java Spring Security con Esempio

Ti consiglio di guardare il pacchetto adbroker del progetto oVirt . Utilizza Spring-Ldap e il modulo di login JBAS Krb5 (con GSSAPI) per autenticare l’utilizzo di Kerberos su server Ldap (Active-Directory, ipa, rhds, Tivoli-DS). Cerca il codice nel motore \ backend \ manager \ modules \ bll \ src \ main \ java \ org \ ovirt \ engine \ core \ bll \ adbroker

Puoi usare git per clonare il repository o navigare usando il link gerrit