57 votes

LDAP bibliothèque Java

Nous sommes en utilisant J2EE afin de développer un produit de sécurité qui s'appuie sur le protocole LDAP pour l'authentification basée sur les rôles, la gestion des utilisateurs.

L'équipe a mis en œuvre cette utilisation de JNDI mais nous avons couru dans les divers pièges. Je suis à la recherche d'un LDAP API qui gère tous les détails de bas niveau et qui satisfait aux exigences suivantes:

  1. L'Utilisateur LDAP authentification et d'Autorisation
  2. De bonnes performances (même avec la grande et de la lenteur des serveurs LDAP)
  3. Soutenir le principal LDAP saveurs (AD, Novell eDirectory, etc.)

Peut-on recommander un open source ou commerciaux paquet?

67voto

fanf42 Points 870

En fait, aujourd'hui, il ya seulement 4 pertinente Java SDK LDAP. D'autres ne sont plus supportés et/ou non mise à jour pour Java 5 et plus:

  • JNDI LDAP est encore le "standard" de choix, mais vous devez les utiliser si et seulement si vous êtes à la FORCE (pour des raisons historiques, par exemple). JNDI LDAP est juste une douleur à utiliser: presque tout ce que vous voulez faire avec elle, c'est dur, même si LDAP est lui-même un vraiment, vraiment protocole simple, et je ne parle même pas de LDAP plus de fonctions d'avance... Mais parfois, vous n'avez tout simplement pas le choix;
  • Printemps LDAP http://www.springsource.org/ldap ; je dirais l'utiliser si et seulement si votre application est déjà en plein Printemps, et vous êtes vraiment utilisé pour le Printemps "modèle" de l'abstraction. Mais en soi, le Printemps LDAP est juste une couche sur le dessus de JNDI, et afin de ne pas apporter de meilleures performances ou d'autres LDAP caractéristiques spécifiques ;
  • les efforts en cours pour construire un nouveau défaut, commun API LDAP, par ApacheDS et OpenDS personnes : http://directory.apache.org/api/ ; il est en phase expérimentale, garder un œil sur ce projet ;
  • et enfin, LE SDK utiliser, à la place JNDI LDAP: UnboundID SDK LDAP http://www.unboundid.com/products/ldapsdk/; Simple pour des cas d'utilisation simples mais néanmoins pleine prise en charge de LDAP, de bonnes performances, de nice, de nouvelles fonctionnalités ont été ajoutées régulièrement (la 2.0 ajouter un objet/d'entrée de la cartographie et de la persistance API), etc.

Donc, si vous avez un seul de garder à l'esprit, juste obtenir UnboundID SDK LDAP.

Edit 2014-04-16: je voudrais ajouter que, depuis un certain temps maintenant, UnboundID ajouté une mémoire du serveur LDAP dans son SDK qui est une merveille pour les tests unitaires (et de prototypage/démo). Exemple d'utilisation: https://www.unboundid.com/products/ldapsdk/docs/javadoc/com/unboundid/ldap/listener/InMemoryDirectoryServer.html. Donc, si vous étiez encore à se demander, maintenant, vous encore moins de raison d': il suffit d'utiliser UnboundID.

45voto

Miles Points 807

LDAP lui-même est déjà offrant un très haut niveau d'abstraction pour les serveurs d'annuaire, je n'ai pas vu beaucoup de bibliothèques qui fournissent une autre abstraction sur le dessus de cela. J'ai écrit ma propre petite bibliothèque pour permettre à ma propre demande à parler à des serveurs LDAP (dans mon cas, également un serveur Active Directory).

Le javax.de nommage.répertoire package est là que les choses intéressantes. Connexion à un serveur LDAP est vraiment pas trop dur...

// set properties for our connection and provider
Properties properties = new Properties();
properties.put( Context.INITIAL_CONTEXT_FACTORY, 
  "com.sun.jndi.ldap.LdapCtxFactory" );
properties.put( Context.PROVIDER_URL, "ldap://myserver.somewhere.com:389"; );
properties.put( Context.REFERRAL, "ignore" );

// set properties for authentication
properties.put( Context.SECURITY_PRINCIPAL, "User Name" );
properties.put( Context.SECURITY_CREDENTIALS, "password" );

InitialDirContext context = new InitialDirContext( properties );

L'exécution de recherches sur l'annuaire n'est pas beaucoup plus difficile.

// Create the search controls
SearchControls searchCtls = new SearchControls();

// Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

// specify the LDAP search filter, just users
String searchFilter = "(&(objectClass=user)( cn=Joe Someone))";

// Specify the attributes to return
String returnedAtts[]={"memberOf"};
searchCtls.setReturningAttributes(returnedAtts);

NamingEnumeration answer = context.search( "dc=com,dc=somewhere", searchFilter, 
  searchCtls );

À partir de là, l'authentification est très facile: la dernière ligne ci-dessus va jeter un NamingException si le nom d'utilisateur et le mot de passe ne sont pas des informations d'identification valides.

J'ai utilisé le Acegi Security bibliothèque à bon escient avec un couple d'applications, l'obtention d'Acegi de travailler avec un backend LDAP est assez simple; cela peut être le plus haut niveau de la solution que vous recherchez.

31voto

Brad Mace Points 12173

Je suis d'accord avec fanf42, j'ai juste envie de s'étendre sur sa réponse. Si vous êtes à l'aide de Printemps de votre choix est facile. Pour le reste d'entre nous, l'API d'Apache n'est pas encore arrivé à maturité et la plupart des autres semblent être laissés à l'abandon, laissant JNDI et UnboundID de l'API LDAP.

Des deux, UnboundID de l'API est beaucoup plus facile à utiliser. Voici un exemple simple de vérifier les références d'un utilisateur:

avec JNDI:

static boolean authenticate(String username, String password) {
    try {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
        props.put(Context.REFERRAL, "ignore");
        props.put(Context.SECURITY_PRINCIPAL, dnFromUser(username));
        props.put(Context.SECURITY_CREDENTIALS, password);

        InitialDirContext context = new InitialDirContext(props);
        return true;
    }
    catch (NamingException e) {
        return false;
    }

}

private static String dnFromUser(String username) throws NamingException {
    Properties props = new Properties();
    props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    props.put(Context.PROVIDER_URL, "ldap://ldap.example.com");
    props.put(Context.REFERRAL, "ignore");

    InitialDirContext context = new InitialDirContext(props);

    SearchControls ctrls = new SearchControls();
    ctrls.setReturningAttributes(new String[] { "givenName", "sn" });
    ctrls.setSearchScope(SearchControls.SUBTREE_SCOPE);

    NamingEnumeration<SearchResult> answers = context.search("dc=People,dc=example,dc=com", "(uid=" + username + ")", ctrls);
    SearchResult result = answers.next();

    return result.getNameInNamespace();
}

avec UnboundID:

static boolean authenticate(String username, String password) throws LDAPException {
    LDAPConnection ldap = new LDAPConnection("ldap.example.com", 389);
    SearchResult sr = ldap.search("dc=People,dc=example,dc=com", SearchScope.SUB, "(uid=" + username + ")");
    if (sr.getEntryCount() == 0)
        return false;

    String dn = sr.getSearchEntries().get(0).getDN();

    try {
        ldap = new LDAPConnection("ldap.example.com", 389, dn, password);
        return true;
    }
    catch (LDAPException e) {
        if (e.getResultCode() == ResultCode.INVALID_CREDENTIALS)
            return false;

        throw e;
    }
}

En plus d'être beaucoup plus courte, de nommage est plus intuitive et il n'y a pas d'obscurs objets intermédiaires pour créer.

6voto

Dmitry Khalatov Points 2172

6voto

duffymo Points 188155

J'ai utilisé du Printemps LDAP modules. Je pense qu'ils font de la programmation avec LDAP aussi simple que l'utilisation de JDBC. Si vous utilisez le Printemps, je les recommande fortement. Si vous ne l'êtes pas, il ya une valeur dans l'apprentissage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X