Sunday, 13 October 2013

Open LDAP Setup in Windows and a Java Spring LDAP Client Development

Objective

To setup an OpenLDAP server in Windows OS and write a LDAP client with standalone Java and Spring libraries.

Environment

  • Windows OS (I have Windows 7)
  • Open LDAP Windows Installer (downloaded from http://userbooster.de/en/download/openldap-for-windows.aspx)
  • LDAP Browser (I have  LDAP browser 2.8.1 by Jarek Gawor)
  • Eclipse IDE

Development

 LDAP Setup

  • Run the downloaded OpenLDAP windows installer; I selected the LDIF backend engine during LDAP setup.
  • You will see a windows service for OpenLDAP server installed.
  • Check if the LDAP is installed properly and service is running by connecting through the LDAP browser you have, for reference I have used following settings to connect to LDAP.
 
  • Now you need some sample data on the LDAP server, so the following entries can be put into a LDIF extension file and added:
dn: ou=groups, dc=maxcrc,dc=com
ou: groups
description: Container for group entries
objectClass: top
objectClass: organizationalUnit

dn: cn=itpeople,ou=groups, dc=maxcrc,dc=com
description: IT security group
objectClass: groupOfNames
member: cn=Sheri Smith,ou=people,dc=maxcrc,dc=com
cn: itpeople

dn: cn=salespeople,ou=groups, dc=maxcrc,dc=com
description: Human Resources group
objectClass: groupOfNames
member: cn=John Smith,ou=people,dc=maxcrc,dc=com
cn: salespeople

dn: ou=People, dc=maxcrc,dc=com
ou: People
objectClass: top
objectClass: organizationalUnit
description: Container for user entries

dn: cn=John Smith,ou=People, dc=maxcrc,dc=com
sn: Smith
userPassword:: alNtaXRI
ou: Sales
carLicense: HISCAR 124
mail: j.smith@maxcrc.com
mail: jsmith@maxcrc.com
mail: john.smith@maxcrc.com
objectClass: inetOrgPerson
uid: jsmith
homePhone: 555-111-2223
cn: John Smith
cn: John J Smith

dn: cn=Sheri Smith,ou=People, dc=maxcrc,dc=com
sn: smith
userPassword:: c1NtaXRI
ou: IT
carLicense: HERCAR 125
mail: s.smith@maxcrc.com
mail: ssmith@maxcrc.com
mail: sheri.smith@maxcrc.com
objectClass: inetOrgPerson
uid: ssmith
homePhone: 555-111-2225
cn: Sheri Smith

  •  To add the above data (copy paste it into some ldif file for example data.ldif) you need to use the LDAP browser import capability or run the following commnad (command available in installed openldap directory):
    • slapadd.exe -l data.ldif
  • You can verify the imported data through LDAP browser.

Java Client

package com.ldap.purjavaclient;

import java.util.Properties;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
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.SearchControls;
import javax.naming.directory.SearchResult;

public class LDAPPurJavaClient {

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            InitialDirContext context = getDirCtx("ldap://localhost",
                    "cn=Manager,dc=maxcrc,dc=com", "secret");
            try {
                if (args != null && args.length > 0) {
                    String input = args[0];
                    switch (input) {
                    case "1":
                        createPerson(context, "Mahesh Chopker", "Mahesh",
                                "mchopker", "Sales");
                        break;
                    case "2":
                        modifyPerson(context, "Mahesh Chopker", "Chopker",
                                "mchopker", "Sales");
                        break;
                    case "3":
                        removePerson(context, "Mahesh Chopker");
                        break;
                    default:
                        searchPerson(context);
                    }
                }
            } finally {
                context.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void searchPerson(InitialDirContext context) {
        Attributes attrs = new BasicAttributes();
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        SearchControls ctls = new SearchControls();
        String[] ret = { "sn", "uid" };
        String filter = "(objectclass=*)";
        ctls.setReturningAttributes(ret);
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        NamingEnumeration<SearchResult> enu = null;
        try {
            enu = context.search("cn=" + "Mahesh Chopker"
                    + ",ou=people,dc=maxcrc,dc=com", filter, ctls);
            while (enu != null && enu.hasMore()) {
                SearchResult sr = (SearchResult) enu.next();
                System.out.println(sr.getNameInNamespace());
                Attributes rattr = sr.getAttributes();
                System.out.println(rattr.get("sn"));
                System.out.println(rattr.get("uid"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (enu != null) {
                try {
                    enu.close();
                } catch (Exception e1) {
                    // igonore this
                }
            }
        }
    }

    private static void createPerson(InitialDirContext context, String name,
            String sn, String uid, String ou) throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people,dc=maxcrc,dc=com";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        SearchResult sr = new SearchResult(dn, null, attrs);
        context.createSubcontext(sr.getName(), attrs);
    }

    private static void modifyPerson(InitialDirContext context, String name,
            String sn, String uid, String ou) throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people,dc=maxcrc,dc=com";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        SearchResult sr = new SearchResult(dn, null, attrs);
        context.modifyAttributes(sr.getName(), DirContext.REPLACE_ATTRIBUTE,
                attrs);
    }

    private static void removePerson(InitialDirContext context, String name)
            throws NamingException {
        context.destroySubcontext(name);
    }

    private static InitialDirContext getDirCtx(String url, String userBindDn,
            String userBindPw) throws Exception {
        InitialDirContext ctx = null;
        Properties env = new Properties();
        env.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        env.setProperty(javax.naming.Context.PROVIDER_URL, url);
        env.setProperty(javax.naming.Context.SECURITY_PRINCIPAL, userBindDn);
        env.setProperty(javax.naming.Context.SECURITY_CREDENTIALS, userBindPw);
        try {
            ctx = new InitialDirContext(env);
        } catch (NamingException ex) {
            throw new Exception("LdapManagerBean::createConnection failed", ex);
        }
        return ctx;
    }
}

Java Spring Client without DI

package com.ldap.springclient;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;

import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;

public class LDAPSpringClient {

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {

            LdapContextSource ldapContextSource = new LdapContextSource();
            ldapContextSource.setUrl("ldap://localhost");
            ldapContextSource.setBase("dc=maxcrc,dc=com");
            ldapContextSource.setUserDn("cn=Manager,dc=maxcrc,dc=com");
            ldapContextSource.setPassword("secret");

            // this line needed since we are not using DI and manually
            // initizlizing context
            ldapContextSource.afterPropertiesSet();

            LdapTemplate ldapTemplate = new LdapTemplate();
            ldapTemplate.setContextSource(ldapContextSource);

            searchPerson(ldapTemplate);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void searchPerson(LdapTemplate ldapTemplate) {
        System.out.println(ldapTemplate.search("cn=Mahesh Chopker,ou=People",
                "(objectclass=*)", new AttributesMapper() {
                    public Object mapFromAttributes(Attributes attrs)
                            throws NamingException {
                        Attributes attributes = new BasicAttributes();
                        attributes.put(attrs.get("cn"));
                        attributes.put(attrs.get("uid"));
                        return attributes;
                    }
                }));
    }
}

Java Spring Client with DI

package com.ldap.springclient;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;

public class LDAPSpringDIClient {

    private LdapTemplate ldapTemplate;

    public void setLdapTemplate(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    "context.xml");
            LDAPSpringDIClient ldapClientInstance = (LDAPSpringDIClient) context
                    .getBean("ldapClient");

            if (args != null && args.length > 0) {
                String input = args[0];
                switch (input) {
                case "1":
                    ldapClientInstance.createPerson("Mahesh K Chopker",
                            "Mahesh", "mchopker", "Sales");
                    break;
                case "2":
                    ldapClientInstance.modifyPerson("Mahesh K Chopker",
                            "Chopker", "mchopker2", "Sales");
                    break;
                case "3":
                    ldapClientInstance.removePerson("Mahesh K Chopker");
                    break;
                default:
                    ldapClientInstance.searchPerson();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createPerson(String name, String sn, String uid, String ou)
            throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        ldapTemplate.bind(dn, null, attrs);
    }

    private void modifyPerson(String name, String sn, String uid, String ou)
            throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        ldapTemplate.rebind(dn, null, attrs);
    }

    private void removePerson(String name) throws NamingException {
        ldapTemplate.unbind(name);
    }

    private void searchPerson() {
        System.out.println(ldapTemplate.search("cn=Mahesh K Chopker,ou=People",
                "(objectclass=*)", new AttributesMapper() {
                    public Object mapFromAttributes(Attributes attrs)
                            throws NamingException {
                        Attributes attributes = new BasicAttributes();
                        attributes.put(attrs.get("cn"));
                        attributes.put(attrs.get("uid"));
                        return attributes;
                    }
                }));
    }
}
 

Testing

  • The test clients have options to add/modify/delete and search LDAP which can be triggered based on the command line input value 1,2,3 and 4.
  • The source code and LDIF data file can be downloaded from following git repository location:
    • https://github.com/mchopker/myprojects/tree/master/LDAPExample

 Thank You!