Connecting and Validating a LDAP with Java for Dummies

Connecting and Validating a LDAP with Java for Dummies

It is very common for many applications to have to authenticate its users (or login). At the

It is very common for many applications to have to authenticate its users (or login). At the same time, these users’ information is often stored in servers. In this particular case, we’ll see how to authenticate a user – with its password – and how to get data from users or groups to a Lightweight Directory Access Protocol (LDAP) server with Java.

How to get connected?

First, one must know which libraries have to be imported, or if any of these libraries must be installed. To use the LDAP server, only the following libraries are needed:

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

To connect to the server, one must load into a Hashtable all the fields we want to send (URL for the connection, user credentials, authentication type, and others that may be necessary), for example:

public static DirContext connectToLDAP(String url, String user, String password) throws NamingException{
  Hashtable<String, String> env = new Hashtable<String, String>();
  env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
  env.put(Context.PROVIDER_URL, url);
  env.put(Context.SECURITY_AUTHENTICATION,"simple");
  env.put(Context.SECURITY_PRINCIPAL, user);
  env.put(Context.SECURITY_CREDENTIALS,password);
  //Conseguimos contexto de conexion
  DirContext ctx = InitialDirContext(env);
  return ctx;
}

In case of not being able to connect to the server with user credentials, an exception will appear (NamingException).

Once connected to the server, we can get the context that allows us to make inquiries, information, authenticate, etc. To log off, one must simply type:

public static void closeConnectionToLDAP(DirContext ctx) {
    try {
        ctx.close();
    } catch (NamingException e) {
        // No se habia podido conectar, ya se habia cerrado la conexion, etc..
        e.printStackTrace();
    }
}

Authenticating a user (with its password)

In order to do so, all one must do is log oneself in a similar manner to that discussed in the previous example, but indicating the corresponding username and password. Note that it is necessary to write the full path (for example, if the username is “john”, it is not enough to simply write as a user “john”), for example: “CN=nombre_usuario,OU=Unidad,DC=dominio”.

If you are able to get connected, you can obtain the context, and if you do not have the correct username or password, the same exception as before will appear:

public boolean correctLogin(username, password) { //El usuario ya viene con toda la ruta
    try {
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, LDAP_URL);
        env.put(Context.SECURITY_AUTHENTICATION,"simple");
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS,password);
        //Conseguimos contexto de conexion
        DirContext ctx = InitialDirContext(env);
        ctx.close();
        return true;
    } catch (NamingException e) {
        return false;
    }
}

Obtaining a user’s or group’s attributes

To do so, one must first get the connection context as indicated above (either as an administrator or common user, but it may depend on the LDAP server).

Then, we need to indicate how many and what are the names of the attributes we want (which could, potentially, be none, if we just want to check whether a user who meets the conditions exists), and the filtering conditions (which are always important although they might be random).

First, we include the following libraries:

import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

For example, we obtain the attributes “field1 ” and ” field2 ” of a given user:

public void search (String username) throws NamingException{ 
    //Recordar que el username tiene que tener toda la ruta de OUs/DCs/CNs
    DirContext context = connectToLDAP(URL, ADMIN, PASS);
    SearchControls ctls = new SearchControls();
    ctls. setReturningObjFlag (true); // Para que devuelva los elementos que buscamos
    
    String returning[] = new String[2];
    returnings[0] = "field1";
    returnings[1] = "fields2";
    //Asignamos los atributos a devolver
    ctls.setReturningAttributes(returning);
    ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
    
    String search = username; // Search es "en donde buscar" de los directorios del servidor
    String filter = "name=" + username; // filtro trivial

    NamingEnumeration answer = ctx.search(search,filter, ctls);       	
    SearchResult result = (SearchResult) answer.next(); // Sabemos que habra un solo resultado
    String field1 = result.getAttributes().get("field1").get().toString();
    String field1 = result.getAttributes().get("field2").get().toString();
    System.out.println(username + ": " + fields1 + ", " + fields2);
 }

The variants that can be sought are enormous, therefore, we propose a more general example of how to perform a search:

public void search (String search, String filter, String[] returningAtts) throws NamingException{ 
    DirContext context = connectToLDAP(URL, ADMIN, PASS);
    SearchControls ctls = new SearchControls();
    ctls. setReturningObjFlag (true); // Para que devuelva los elementos que buscamos
    
    //Asignamos los atributos a devolver
    ctls.setReturningAttributes(returningAtts);
    ctls.setSearchScope(SearchControls.OBJECT_SCOPE);

    NamingEnumeration answer = ctx.search(search,filter, ctls);  
    while (answer.hasNext()){
        SearchResult result = (SearchResult) answer.next();
        HashMap map = new HashMap();
        for (String returning : returningAtts){
             map.put(returning, result.getAttributes().get("returning").get().toString());
        }
        doSomething(map);
    }     	
}

Example of use:

search("DC=dominio_general,OU=org", "userType=Admin", {"username", "mail"});

Conclusions

It is very easy to authenticate and inquire information from a LDAP server in Java, and the code can be relatively simple and easy to understand (although as the query becomes more complex, so does the code).

On the downside, we can see that it is necessary to indicate where we want the query to inquire the information (knowing the whole structure of LDAP), but more importantly, it must be given in the correct order; otherwise the query will fail.

Are you searching for the best technical solution for your company? Do not hesitate to Contact us for more information. ¡We will get back to you!