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 ;-)

Google+

15 Comments

Jonathan

about 5 years ago

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];

Reply

edwin

about 5 years ago

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

Destrey

about 5 years ago

Your airtcle was excellent and erudite.

Reply

edwin

about 5 years ago

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.

Ben

about 5 years ago

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!

Reply

edwin

about 5 years ago

Hi Ben, glad i could help you and thank you for your wishes :D

Chandra Sekar

about 4 years ago

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

Reply

edwin

about 4 years ago

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);

Balu

about 4 years ago

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...

Reply

edwin

about 4 years ago

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];)

Harri

about 3 years ago

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

Reply

edwin

about 3 years ago

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.

Rolyer Luo

about 2 years ago

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];

Reply

edwin

about 2 years ago

hi Rolyer, looks like your ldap connection is problematic :(

athar

about 7 months ago

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.

Reply

Leave a Comment

Please be polite. We appreciate that.
Your email address will not be published and required fields are marked


:-[ (B) (^) (P) (@) (O) (D) :-S ;-( (C) (&) :-$ (E) (~) (K) (I) (L) (8) :-O (T) (G) (F) :-( (H) :-) (*) :-D (N) (Y) :-P (U) (W) ;-)