LDAP Programming with Java

Today im trying to share on how to do a simple LDAP queries such as select, insert, edit and delete using java. Im using Apache Directory Server as LDAP server and JXplorer as LDAP explorer.

Enough chit-chat, here is my code.
First is a simple java bean,

package com.edw.bean;

/**
 *  com.edw.bean.Person
 *
 *  @author edw
 */
public class Person {
    
    private String name;
    private String address;    
    private String password;

	// other setter and getter
}

and here is my LDAP class controller

package com.edw.ldap.main;

import com.edw.bean.Person;
import java.security.MessageDigest;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.log4j.Logger;
import sun.misc.BASE64Encoder;

/**
 *  com.edw.ldap.main.LDAPMain
 *
 *  @author edw
 */
public class LDAPMain {

    private Logger logger = Logger.getLogger(LDAPMain.class);
    private Hashtable<String, String> env = new Hashtable<String, String>();

    public LDAPMain() {
        try {
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            env.put(Context.PROVIDER_URL, "ldap://localhost:10389");
            env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
            env.put(Context.SECURITY_CREDENTIALS, "xxx");
        } catch (Exception e) {
            logger.error(e, e);
        }

    }

    private boolean insert(Person person) {
        try {

            DirContext dctx = new InitialDirContext(env);
            Attributes matchAttrs = new BasicAttributes(true);
            matchAttrs.put(new BasicAttribute("uid", person.getName()));
            matchAttrs.put(new BasicAttribute("cn", person.getName()));
            matchAttrs.put(new BasicAttribute("street", person.getAddress()));
            matchAttrs.put(new BasicAttribute("sn", person.getName()));
            matchAttrs.put(new BasicAttribute("userpassword", encryptLdapPassword("SHA", person.getPassword())));
            matchAttrs.put(new BasicAttribute("objectclass", "top"));
            matchAttrs.put(new BasicAttribute("objectclass", "person"));
            matchAttrs.put(new BasicAttribute("objectclass", "organizationalPerson"));
            matchAttrs.put(new BasicAttribute("objectclass", "inetorgperson"));
            String name = "uid=" + person.getName() + ",ou=users,ou=system";
            InitialDirContext iniDirContext = (InitialDirContext) dctx;
            iniDirContext.bind(name, dctx, matchAttrs);

            logger.debug("success inserting "+person.getName());
            return true;
        } catch (Exception e) {
            logger.error(e, e);
            return false;
        }
    }

    private boolean edit(Person person) {
        try {

            DirContext ctx = new InitialDirContext(env);
            ModificationItem[] mods = new ModificationItem[2];
            Attribute mod0 = new BasicAttribute("street", person.getAddress());
            Attribute mod1 = new BasicAttribute("userpassword", encryptLdapPassword("SHA", person.getPassword()));
            mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, mod0);
            mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, mod1);

            ctx.modifyAttributes("uid=" + person.getName() + ",ou=users,ou=system", mods);

            logger.debug("success editing "+person.getName());
            return true;
        } catch (Exception e) {
            logger.error(e, e);
            return false;
        }
    }

    private boolean delete(Person person) {
        try {

            DirContext ctx = new InitialDirContext(env);
            ctx.destroySubcontext("uid=" + person.getName() + ",ou=users,ou=system");

            logger.debug("success deleting "+person.getName());
            return true;
        } catch (Exception e) {
            logger.error(e, e);
            return false;
        }
    }
    
    private boolean search(Person person) {
        try {

            DirContext ctx = new InitialDirContext(env);
            String base = "ou=users,ou=system";

            SearchControls sc = new SearchControls();
            sc.setSearchScope(SearchControls.SUBTREE_SCOPE);

            String filter = "(&(objectclass=person)(uid="+person.getName()+"))";

            NamingEnumeration results = ctx.search(base, filter, sc);


            while (results.hasMore()) {
                SearchResult sr = (SearchResult) results.next();
                Attributes attrs = sr.getAttributes();

                Attribute attr = attrs.get("uid");
                if(attr != null)
                    logger.debug("record found "+attr.get());
            }
            ctx.close();
                        
            return true;
        } catch (Exception e) {
            logger.error(e, e);
            return false;
        }
    }

    private String encryptLdapPassword(String algorithm, String _password) {
        String sEncrypted = _password;
        if ((_password != null) && (_password.length() > 0)) {
            boolean bMD5 = algorithm.equalsIgnoreCase("MD5");
            boolean bSHA = algorithm.equalsIgnoreCase("SHA")
                    || algorithm.equalsIgnoreCase("SHA1")
                    || algorithm.equalsIgnoreCase("SHA-1");
            if (bSHA || bMD5) {
                String sAlgorithm = "MD5";
                if (bSHA) {
                    sAlgorithm = "SHA";
                }
                try {
                    MessageDigest md = MessageDigest.getInstance(sAlgorithm);
                    md.update(_password.getBytes("UTF-8"));
                    sEncrypted = "{" + sAlgorithm + "}" + (new BASE64Encoder()).encode(md.digest());
                } catch (Exception e) {
                    sEncrypted = null;
                    logger.error(e, e);
                }
            }
        }
        return sEncrypted;
    }

    public static void main(String[] args) {
        LDAPMain main = new LDAPMain();

        Person person = new Person();
        person.setAddress("kebayoran");
        person.setName("kamplenk");
        person.setPassword("pepe");

        // insert
        main.insert(person);
        
        // edit
        main.edit(person);
        
        // select
        main.search(person);
        
        // delete
        main.delete(person);
    }
}

Here is screenshot of my LDAP explorer, after i’ve insert my latest ldap record.

hope it can help others, have fun with LDAP ๐Ÿ˜‰

15 thoughts on “LDAP Programming with Java”

  1. Thank you for the awesome post.
    Does anyone know what I’m missing if I’m getting the following error:
    [LDAP: error code 53 – no global superior knowledge];

    1. ho jonathan,
      could you please put a simple snippet of your java code, especially on this part

      Context.PROVIDER_URL

      Likely the entry name is incorrect, or the server is not properly configured to hold the named entry. Please see this link

    1. hi Destrey, thanks. I had to look the dictionary for the meaning of erudite.

      erยทuยทdite? ?[er-yoo-dahyt, er-oo-]
      adjective
      characterized by great knowledge; learned or scholarly: an erudite professor; an erudite commentary.

  2. Edwin,
    Thanks a ton for this post. I have been struggling for over a week now, trying to create a web service layer around our LDAP server. I got a simple CRUD app working with Spring LDAP. But as soon as I added EJB3.1 web services into the mix, it broke; I couldn’t figure out how to inject a properly initialized LdapTemplate object in my bean. After having gone though this post, I now have my EJB web services talking to my LDAP server!
    Also, congratulations on your recent wedding!

  3. Chandra Sekar

    Hi Edwin,

    This is really a very good post foe the learners. Thank you so much for that. I have a question that can we retrieve the password from LDAP in a clear text? using LDAP Apis?

    Regards,
    Chandra

    1. Hi Chandra Sekar,
      if im not wrong, it’s depend on how you store your password on ldap, whether using md5, plain or sha-1.
      If you set your password as plain text format, i think you could get your password in a clear text result.
      But it will provide your password in byte[] format, you need to convert it into String
      String s = new String(bytes);

  4. Error javax.naming.NameNotFoundException: [LDAP: error code 32 – NO_SUCH_OBJECT: failed for MessageType : ADD_REQUEST
    Message ID : 2
    Add Request :
    Entry
    dn[n]: uid=kamplenk,ou=users,ou=system,dc=example,dc=com
    objectclass: inetorgperson
    uid: kamplenk
    sn: kamplenk
    userpassword: ‘0x74 0x65 0x73 0x74 0x74 0x65 0x73 0x74 ‘
    cn: kamplenk
    street: kebayoran
    ManageDsaITImpl Control
    Type OID : ‘2.16.840.1.113730.3.4.2’
    Criticality : ‘false’

    : ERR_251_PARENT_NOT_FOUND Parent ou=users,ou=system,dc=example,dc=com not found]; remaining name ‘uid=kamplenk,ou=users,ou=system’

    hi,
    i am using same code for inserting new record,i got above error.i dint use password encrypt code,instead of that i used “matchAttrs.put(new BasicAttribute(“userpassword”,person.getPassword()))”.

    connection details:

    env.put(Context.INITIAL_CONTEXT_FACTORY, “com.sun.jndi.ldap.LdapCtxFactory”);
    env.put(Context.PROVIDER_URL, “ldap://localhost:10389/dc=example,dc=com”);
    env.put(Context.SECURITY_PRINCIPAL, “uid=admin,ou=system”);
    env.put(Context.SECURITY_CREDENTIALS, “secret”);
    .

    can u plz help…

    1. Hi Balu,
      could you please provide me with your ldap structure, because your error somehow due to missconfiguration of your ldap structure (Parent ou=users,ou=system,dc=example,dc=com not found];)

  5. hi
    Excellent examples of good programming with jndi & java, really really clear, best i’ve seen for a while

    One question though

    Method: encryptLdapPassword(String, String)
    what if you need to encrypt the password with SSHA instead of sha-1, md5 etc. Does it work by just passing SSHA as to method, need to test..
    br, Harri

    1. Hi Harri,
      never tested with SSHA before,
      But if im not wrong, you could use plain password, but sending the password in SSHA encryption instead of just plain.

  6. Does anyone know what I’m missing if I’m getting the following error:
    ERROR javax.naming.directory.InvalidAttributeIdentifierException: [LDAP: error code 17 – dn: attribute type undefined];

  7. Dear edwin, your code is beautiful ๐Ÿ™‚ , but there is an issue, that i have an already created user in my AD, whemn i want to delete it , it gets deleted programatically but when i open my active directory that user is still there. and also when i try to create a user with the admin security, it give credentials (wrong password) error,althoough my credentials are corrrect.

Leave a Reply to Harri Cancel Reply

Your email address will not be published.