Authentification contre Active Directory avec Java sous Linux

J’ai une tâche simple d’authentification sur Active Directory en utilisant Java. Il suffit de vérifier les informations d’identification et rien d’autre. Disons que mon domaine est “fun.xyz.tld”, que le chemin de l’unité d’organisation est inconnu et que le nom d’utilisateur / mot de passe est testu / testp.

Je sais qu’il existe quelques bibliothèques Java qui simplifient cette tâche, mais je n’ai pas réussi à les implémenter. La plupart des exemples que j’ai trouvés concernaient LDAP en général, pas spécifiquement Active Directory. Emettre une requête LDAP signifie envoyer un chemin d’access à l’unité d’organisation, ce que je n’ai pas. En outre, l’application qui émet la requête LDAP doit déjà être liée à Active Directory pour y accéder … Insécurité, car les informations d’identification doivent être stockées à un endroit découvrable. Je voudrais un test de liaison avec des informations d’identification de test, si possible – cela voudrait dire que ce compte est valide.

Enfin, si possible, existe-t-il un moyen de chiffrer un tel mécanisme d’authentification? Je sais que AD utilise Kerberos, mais je ne sais pas si les méthodes LDAP de Java le font.

Est-ce que quelqu’un a un exemple de code de travail? Merci.

    Trois protocoles d’authentification peuvent être utilisés pour effectuer l’authentification entre Java et Active Directory sur Linux ou toute autre plate-forme (et ils ne sont pas spécifiques aux services HTTP):

    1. Kerberos – Kerberos fournit l’authentification unique (SSO) et la délégation, mais les serveurs Web ont également besoin de la prise en charge de SPNEGO pour accepter la connexion unique via IE.

    2. NTLM – NTLM prend en charge l’authentification unique via IE (et les autres navigateurs s’ils sont correctement configurés).

    3. LDAP – Une liaison LDAP peut être utilisée pour simplement valider un nom de compte et un mot de passe.

    Il y a aussi quelque chose appelé “ADFS” qui fournit la SSO pour les sites Web utilisant SAML qui appelle dans le SSP Windows. En pratique, c’est essentiellement une manière détournée d’utiliser l’un des autres protocoles ci-dessus.

    Chaque protocole a ses avantages, mais en règle générale, pour une compatibilité maximale, vous devriez généralement essayer de “faire comme Windows”. Alors, que fait Windows?

    Premièrement, l’authentification entre deux machines Windows favorise Kerberos, car les serveurs n’ont pas besoin de communiquer avec le contrôleur de domaine et les clients peuvent mettre en cache les tickets Kerberos, ce qui réduit la charge sur les contrôleurs.

    Mais si les parties authentifiantes ne possèdent pas toutes les deux des comptes de domaine ou si le client ne peut pas communiquer avec le contrôleur de domaine, NTLM est requirejs. Ainsi, Kerberos et NTLM ne s’excluent pas mutuellement et NTLM n’est pas obsolète avec Kerberos. En fait, à certains égards, NTLM est meilleur que Kerberos. Notez que lorsque vous mentionnez Kerberos et NTLM dans le même souffle, je dois également mentionner SPENGO et l’authentification Windows intégrée (IWA). IWA est un terme simple qui signifie essentiellement Kerberos, NTLM ou SPNEGO pour négocier Kerberos ou NTLM.

    L’utilisation d’une liaison LDAP pour valider les informations d’identification n’est pas efficace et requirejs SSL. Cependant, jusqu’à récemment, la mise en œuvre de Kerberos et de NTLM était difficile, de sorte que l’utilisation de LDAP en tant que service d’authentification de substitution a persisté. Mais à ce stade, il devrait généralement être évité. LDAP est un répertoire d’informations et non un service d’authentification. Utilisez-le pour son but prévu.

    Alors, comment implémentez-vous Kerberos ou NTLM en Java et dans le contexte des applications Web en particulier?

    Il existe un certain nombre de grandes entresockets comme Quest Software et Censortingfy qui ont des solutions qui mentionnent spécifiquement Java. Je ne peux pas vraiment les commenter, car ce sont des “solutions de gestion d’identité” à l’échelle de l’entreprise. Il est donc difficile de déterminer exactement quels protocoles sont utilisés et comment ils fonctionnent. Vous devrez les contacter pour les détails.

    L’implémentation de Kerberos en Java n’est pas très difficile, car les bibliothèques Java standard prennent en charge Kerberos via les classes org.ietf.gssapi. Cependant, jusqu’à récemment, il y a eu un obstacle majeur: IE n’envoie pas de jetons Kerberos bruts, il envoie des jetons SPNEGO. Mais avec Java 6, SPNEGO a été implémenté. En théorie, vous devriez pouvoir écrire du code GSSAPI capable d’authentifier les clients IE. Mais je n’ai pas essayé. L’implémentation de Sun de Kerberos a été une comédie d’erreurs au fil des ans. Si je me base sur les antécédents de Sun dans ce domaine, je ne ferais aucune promesse sur leur implémentation SPENGO avant d’avoir cet oiseau en main.

    Pour NTLM, il existe un projet Free OSS appelé JCIFS qui possède un filtre de servlet d’authentification HTTP NTLM. Cependant, il utilise une méthode man-in-the-middle pour valider les informations d’identification avec un serveur SMB qui ne fonctionne pas avec NTLMv2 (qui devient progressivement une stratégie de sécurité de domaine requirejse). Pour cette raison et pour d’autres, la partie Filtre HTTP de JCIFS doit être supprimée. Notez que plusieurs spin-offs utilisent JCIFS pour implémenter la même technique. Donc, si vous voyez d’autres projets qui prétendent prendre en charge l’authentification unique NTLM, vérifiez les petits caractères.

    La seule méthode correcte pour valider les informations d’identification NTLM avec Active Directory consiste à utiliser l’appel DCERPC NetrLogonSamLogon sur NETLOGON avec Secure Channel. Est-ce qu’une telle chose existe en Java? Oui. C’est ici:

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

    Jespa est une implémentation 100% Java NTLM qui prend en charge NTLMv2, NTLMv1, les options d’intégrité et de confidentialité complètes et la validation des informations d’identification NETLOGON susmentionnée. Et il comprend un filtre SSO HTTP, un LoginModule JAAS, un client HTTP, un client et un serveur SASL (avec liaison JNDI), un “fournisseur de sécurité” générique pour la création de services NTLM personnalisés, etc.

    Mike

    Voici le code que j’ai mis en place, basé sur l’exemple de ce blog: LINK et cette source: 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.Atsortingbute; import javax.naming.directory.Atsortingbutes; 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(Ssortingng[] 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); } Ssortingng domainName; Ssortingng serverName; if (args.length == 4) { domainName = args[2]; serverName = args[3]; } else { domainName = "xyz.tld"; serverName = "abc"; } Ssortingng username = args[0]; Ssortingng password = args[1]; System.out .println("Authenticating " + username + "@" + domainName + " through " + serverName + "." + domainName); // bind by using the specified username/password Hashtable props = new Hashtable(); Ssortingng 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(); Atsortingbute memberOf = result.getAtsortingbutes().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.toSsortingng(); } } 

    Je viens de terminer un projet qui utilise AD et Java. Nous avons utilisé Spring ldapTemplate.

    AD est compatible avec LDAP (presque), je ne pense pas que vous aurez des problèmes avec la tâche que vous avez. Je veux dire le fait qu’il s’agit d’une AD ou de tout autre serveur LDAP, peu importe si vous voulez juste vous connecter.

    Je voudrais jeter un coup d’oeil à: Spring LDAP

    Ils ont aussi des exemples.

    En ce qui concerne le cryptage, nous avons utilisé la connexion SSL (c’était donc LDAPS). AD devait être configuré sur un port / protocole SSL.

    Mais avant tout, assurez-vous de pouvoir vous connecter correctement à votre AD via un IDE LDAP. J’utilise Apache Directory Studio , c’est vraiment cool, et c’est écrit en Java. C’est tout ce dont j’avais besoin. A des fins de test, vous pouvez également installer Apache Directory Server

    Comme ioplex et d’autres l’ont dit, il existe de nombreuses options. Pour m’authentifier à l’aide de LDAP (et de l’API Novell LDAP), j’ai utilisé quelque chose comme:

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

    En tant que “fonctionnalité spéciale”, Active Directory autorise les liaisons LDAP avec “utilisateur @ domaine” sans utiliser le nom distinctif du compte. Ce code utilise StartTLS pour activer le chiffrement TLS sur la connexion; L’autre alternative est LDAP sur SSL, qui n’est pas pris en charge par mes serveurs AD.

    Le vrai truc consiste à localiser le serveur et l’hôte; la manière officielle est d’utiliser une recherche d’enregistrement DNS SRV (service) pour localiser un ensemble d’hôtes candidats, puis effectuer un “ping” LDAP basé sur UDP (dans un format Microsoft particulier) pour localiser le serveur approprié. Si vous êtes intéressé, j’ai posté des articles sur mon parcours d’aventure et de découverte dans ce domaine.

    Si vous voulez faire une authentification par nom d’utilisateur / mot de passe basée sur Kerberos, vous regardez une autre marmite de poisson; il est faisable avec le code Java GSS-API, même si je ne suis pas sûr qu’il effectue la dernière étape pour valider l’authentification. (Le code effectuant la validation peut contacter le serveur AD pour vérifier le nom d’utilisateur et le mot de passe, ce qui entraîne un ticket d’octroi de ticket pour l’utilisateur, mais pour s’assurer que le serveur AD ne soit pas emprunté) l’utilisateur à lui-même, ce qui est un peu plus compliqué.)

    Si vous souhaitez effectuer une connexion unique basée sur Kerberos, en supposant que vos utilisateurs soient authentifiés sur le domaine, vous pouvez également le faire avec le code Java GSS-API. Je publierais un exemple de code, mais je dois encore transformer mon prototype hideux en quelque chose qui convienne aux yeux de l’homme. Découvrez du code de SpringSource pour vous inspirer.

    Si vous êtes à la recherche de NTLM (ce qui m’a été donné à comprendre est moins sûr) ou autre chose, bon courage.

    Êtes-vous juste en train de vérifier les informations d’identification? Dans ce cas, vous pouvez simplement faire des kerberos simples et ne pas vous soucier de LDAP .

    Si tout ce que vous voulez faire est de vous authentifier avec AD en utilisant Kerberos, alors un simple programme http://spnego.sourceforge.net/HelloKDC.java devrait le faire.

    Jetez un coup d’oeil à la documentation “pré-vol” du projet qui parle du programme HelloKDC.java.

    L’authentification ldap sans SSL n’est pas sûre et n’importe qui peut afficher les informations d’identification de l’utilisateur car le client ldap transfère usernamae et le mot de passe pendant l’opération de liaison ldap. Utilisez donc toujours le protocole ldaps. source: authentification Ldap Active Directory dans Java Spring Security avec exemple

    Je vous recommande de consulter le package adbroker du projet oVirt . Il utilise Spring-Ldap et le module de connexion JAAS de Krb5 (avec GSSAPI) pour s’authentifier à l’aide de Kerberos contre les serveurs Ldap (Active-Directory, ipa, rhds, Tivoli-DS). Recherchez le code dans le moteur \ backend \ manager \ modules \ bll \ src \ main \ java \ org \ ovirt \ engine \ core \ bll \ adbroker

    Vous pouvez utiliser git pour cloner le référentiel ou parcourir le lien gerrit