web-dev-qa-db-fra.com

Comment vérifier le mot de passe de l'utilisateur dans LDAP Whith Java avec LDAPContext?

J'ai une application Web, où les utilisateurs doivent se connecter. Le mot de passe est stocké dans un serveur LDAP. Toutes les informations sur le serveur LDAP sont stockées dans le serveur d'applications (Glassfish) comme ressource JNDI externe. Donc, mon application ne sais rien sur le serveur LDAP et obtient uniquement un LDAPContext comme celui-ci:

@Resource(name = "ldap/users")
private LdapContext ctx;

Avec ce contexte, il est facile de changer ou de lire les informations stockées pour les utilisateurs, mais comment puis-je vérifier leurs mots de passe? Normalement, je ferais simplement une nouvelle connexion pour vérifier le mot de passe des utilisateurs. Comme ça:

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");

env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=S. User, ou=NewHires, o=JNDITutorial");
env.put(Context.SECURITY_CREDENTIALS, "mysecret");

DirContext ctx = new InitialDirContext(env);

Mais puisque je ne connais pas ce paramètre, je ne peux pas faire cela. Alors, comment puis-je vérifier si le mot de passe d'un utilisateur est correct avec mon LDAPContext? Les mots de passe sont stockés cryptés (SSHA) afin que je ne puisse pas simplement comparer les attributs.

Merci raffael

18
raffael

Vous devriez pouvoir obtenir l'environnement du contexte LDAP, le cloner, puis mettre les principaux et les informations d'identification de l'utilisateur que vous souhaitez vérifier:

@Resource(name = "ldap/users")
private LdapContext ldapContext;

Hashtable environment = ldapContext.getEnvironment().clone();
environment.put(Context.SECURITY_PRINCIPAL, userDN);
environment.put(Context.SECURITY_CREDENTIALS, userPassword);

DirContext dirContext = new InitialDirContext(environment);
10
Brandon

Il s'agit d'une solution qui peut être utilisée pour authentifier un utilisateur avec autre chose que le DN, par exemple avec un uid ou sAMAccountName.

Les étapes à suivre sont:

  1. Connectez-vous au serveur LDAP
  2. Authentifier avec un utilisateur de service dont nous connaissons le DN et les informations d'identification
  3. Recherchez l'utilisateur que vous souhaitez authentifier, recherchez-lui un attribut (par exemple sAMAccountName)
  4. Obtenez le DN de l'utilisateur que nous avons trouvé
  5. Ouvrez une autre connexion au serveur LDAP avec le DN trouvé et le mot de passe
  6. Si l'utilisateur est trouvé et que l'authentification fonctionne, vous allez bien

Exemple de code:

public static boolean performAuthentication() {

    // service user
    String serviceUserDN = "cn=Mister Service,ou=Users,dc=example,dc=com";
    String serviceUserPassword = "abc123#!$";

    // user to authenticate
    String identifyingAttribute = "uid";
    String identifier = "maxdev";
    String password = "jkl987.,-";
    String base = "ou=Users,dc=example,dc=com";

    // LDAP connection info
    String ldap = "localhost";
    int port = 10389;
    String ldapUrl = "ldap://" + ldap + ":" + port;

    // first create the service context
    DirContext serviceCtx = null;
    try {
        // use the service user to authenticate
        Properties serviceEnv = new Properties();
        serviceEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
        serviceEnv.put(Context.PROVIDER_URL, ldapUrl);
        serviceEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
        serviceEnv.put(Context.SECURITY_PRINCIPAL, serviceUserDN);
        serviceEnv.put(Context.SECURITY_CREDENTIALS, serviceUserPassword);
        serviceCtx = new InitialDirContext(serviceEnv);

        // we don't need all attributes, just let it get the identifying one
        String[] attributeFilter = { identifyingAttribute };
        SearchControls sc = new SearchControls();
        sc.setReturningAttributes(attributeFilter);
        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);

        // use a search filter to find only the user we want to authenticate
        String searchFilter = "(" + identifyingAttribute + "=" + identifier + ")";
        NamingEnumeration<SearchResult> results = serviceCtx.search(base, searchFilter, sc);

        if (results.hasMore()) {
            // get the users DN (distinguishedName) from the result
            SearchResult result = results.next();
            String distinguishedName = result.getNameInNamespace();

            // attempt another authentication, now with the user
            Properties authEnv = new Properties();
            authEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.Sun.jndi.ldap.LdapCtxFactory");
            authEnv.put(Context.PROVIDER_URL, ldapUrl);
            authEnv.put(Context.SECURITY_PRINCIPAL, distinguishedName);
            authEnv.put(Context.SECURITY_CREDENTIALS, password);
            new InitialDirContext(authEnv);

            System.out.println("Authentication successful");
            return true;
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (serviceCtx != null) {
            try {
                serviceCtx.close();
            } catch (NamingException e) {
                e.printStackTrace();
            }
        }
    }
    System.err.println("Authentication failed");
    return false;
}
24
Nikolay Antipov