blogger templates blogger widgets
This is part of a list of blog posts.
To browse the contents go to

Real Time Scenario - Configuring LDAP authentication

How to authenticate a user by uid and password?

If you want to use simple binds with user DN and password within a Java component, in order to authenticate users programatically, in practice one problem arises: Most users do not know their DN. Therefore they will not be able to enter it.


It would be easier for a user if s/he only has to provide a short, unique ID and the password. And that's how most websites handle it.

Let's see how to authenticate a user who provides John Eipe/qwer1234 instead of cn=John Eipe, ou=employees, o=csRepository/qwer1234 with the help of ApacheDS.

ApacheDS site provides a simple algorithm that can be followed.

Arguments
  • a attribute like cn or uid
  • password proclaimed to be correct for the user
  • Steps
  • Bind to ApacheDS anonymously, or with the DN of a technical user. In both cases it must be possible to search the directory afterwards (authorization has to be configured that way)
  • Perform a search operation with an appropriate filter to find the user entry for the given ID, in our case "(&(objectClass=organizationalPerson)(cn=John Eipe))"
    • If the search result is empty, the user does not exist -- terminate
    • If the search result contains more than one entry, the given ID is not unique, this is likely a data error within your directory
  • Bind to ApacheDS with the DN of the entry found in the previous search, and the password provided as argument
    • If the bind operation fails, the password is wrong, and the result is false (not authenticated)
    • If the bind is successful, authenticate the user

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class MainClass {
 @SuppressWarnings({ "unchecked", "rawtypes" })
 public static void main(String[] args) {
  // input
  String cn = "John Eipe";
  String password = "qwer1234";
  
  Hashtable env = new Hashtable();
  env.put(Context.INITIAL_CONTEXT_FACTORY,
    "com.sun.jndi.ldap.LdapCtxFactory");
  env.put(Context.PROVIDER_URL, "ldap://localhost:10389");
  env.put(Context.SECURITY_AUTHENTICATION, "simple");
  

  DirContext ctx = null;

  try {
   // Step 1: Bind anonymously
   ctx = new InitialDirContext(env);

   // Step 2: Search the directory
   String base = "o=csRepository";
   String filter = "(&(objectClass=person)(cn={0}))";
   SearchControls ctls = new SearchControls();
   ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
   ctls.setReturningAttributes(new String[0]);
   ctls.setReturningObjFlag(true);
   NamingEnumeration enm = ctx.search(base, filter, new String[] { cn }, ctls);

   String dn = null;

   if (enm.hasMore()) {
    SearchResult result = (SearchResult) enm.next();
    dn = result.getNameInNamespace();

    System.out.println("dn: " + dn);
   }

   if (dn == null || enm.hasMore()) {
    // uid not found or not unique
    throw new NamingException("Authentication failed");
   }

   // Step 3: Bind with found DN and given password
   ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
   ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
   // Perform a lookup in order to force a bind operation with JNDI
   ctx.lookup(dn);
   System.out.println("Authentication successful");

   enm.close();
  } catch (NamingException e) {
   System.out.println(e.getMessage());
  } finally {
   try {
    ctx.close();
   } catch (NamingException e) {
    e.printStackTrace();
   }
  }
 }
}

Output:
dn: cn=John Eipe,ou=employees,o=csRepository
Authentication successful

No comments:

Post a Comment