A Simple LDAP Query Program in Java.

January 23, 2008

The need to query LDAP directories arises surprisingly rarely for me. As such, each time, I essentially need to relearn how to do this.

I recently contributed to a PHP based project in which LDAP queries would be needed in certain circumstances, once per session. But in the deployment environment, PHP had not been compiled with LDAP support, and I couldn’t ask for this to be updated.

So, I decided to write the needed function in Java, knowing that LDAP support is part of the Java standard libraries and the server we were deploying to was a Solaris machine, so I knew Java would be available. I could then call the Java program from PHP. Clearly, this approach is far from perfect, but its portable and ultimately I felt it was the best way to work within the constraints of the system. And because such queries would only be executed once a session–and only for certain users–the performance hit of this approach was acceptable.

Google is definitely my friend, and I quickly found a great turorial (unfortunately from Google cache–I can’t find it on the original site) to refresh my knowledge of querying LDAP, and started modifying the Java example given there. In my situation, I would know a user’s identifier and want to get their status at Cornell University, whether they are faculty, staff, a student, an alumnus, etc. So, I want to query for an attribute of a known record, which is to say, I only needed a narrowly defined way of querying LDAP that fit my particular situation, but I suspect this situation is common enough that others may find it useful:

import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;

public class SimpleQuery {

    public static void main(String[] args) {

        if (args.length != 2) {
          System.out.println("Syntax: SimpleQuery query attribute");
          return;
        }

        String query = args[0];
        String attribute = args[1];
        StringBuffer output = new StringBuffer();

        try {
            String url = "ldap://directory.cornell.edu/o=Cornell%20University,c=US";
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            env.put(Context.PROVIDER_URL, url);
            DirContext context = new InitialDirContext(env);

            SearchControls ctrl = new SearchControls();
            ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
            NamingEnumeration enumeration = context.search("", query, ctrl);
            while (enumeration.hasMore()) {
                SearchResult result = (SearchResult) enumeration.next();
                Attributes attribs = result.getAttributes();
                NamingEnumeration values = ((BasicAttribute) attribs.get(attribute)).getAll();
                while (values.hasMore()) {
                  if (output.length() > 0) {
                    output.append("|");
                  }
                  output.append(values.next().toString());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.print(output.toString());
    }

    public SimpleQuery() {}
}

Obviously, you will need to change the “url” variable for the LDAP directory you want to access, and you’ll probably feel much better if you populate this from an external property file. Also note that I am connecting anonymously to the LDAP directory, because in my case, I was only interested in retrieving publicly available information.

I wrote this in a way that compiles under Java 1.4, which was the version of Java on that server–another constraint I had to deal with. Therefore, I used casting instead of generics, StringBuffer instead of StringBuilder, etc. Ah, nostalgia. If you want to use this under Java 1.5, you can make the code a little more concise.

Cornell University uses Kerberos for centralized authentication, and they produce an Apache module that, once configured for a resource under Apache, redirects to a login page and upon successful authentication, returns to the resource with REMOTE_USER populated with the user’s identifier. Having REMOTE_USER populated then, one can assume that the user successfully authenticated and is a member of the Cornell University community. That user’s identifier is stored in the “uid” attribute of their LDAP record, so with it, I can get some information about that user using the Java program above:

<?php
$netID = getenv('REMOTE_USER');
if (isset($netID) && $netID != '') {
  $_SESSION['primary_affiliation'] = exec('java SimpleQuery uid=' . $netID . 'eduPersonPrimaryAffiliation');
}
?>

This PHP code is embedded within the resource configured to require authentication. In the Cornell LDAP directory, the “eduPersonPrimaryAffiliation” attribute contains strings like “alumni”, “staff”, etc. and I expect it to return one and only one value per person queried, so if you adopt this technique, you may need to perform extra checks.

29 Comments

Comment by Qasim awan
2008-04-11 04:45:15

its really very nice and helpful article!

nice work dear!

 
Comment by Sam
2008-07-07 02:19:39

Thanks a lot for taking time to post it …
must appreciate your heart to share it.

 
Comment by Bava
2008-07-17 01:40:21

Thanks a lot! very helpful article.

 
Comment by Chandra
2008-07-17 16:07:43

I am trying to get the users from LDAP who are created after a certain date. I am struggling with this. Do i write a standard SQL query and pass it on to the InitialDirContext.search? Can you please provide an example for the search query.

Comment by admin
2008-07-17 18:19:22

Chandra,

This will show you how to approach your query: http://tools.ietf.org/html/rfc4515

 
 
Comment by Rakesh
2008-10-14 07:49:44

I am trying to get the roles associated with the user from Ldap. I got till the user authentication but i have no idea how to get the user roles. I am new to Ldap and java. Any help is much appreciated.

Comment by admin
2008-10-14 07:56:34

Rakesh,

Do you know the attribute that your user roles are stored in?

Comment by Rakesh
2008-10-14 08:12:24

Hi,
The attribute name pdsRoles. This is the code that i have till now.
Hashtable authEnv = new Hashtable(11);
String userName = “matthews”;
String password = “abc123”;
String base = “ou=people,o=banner.iit.edu,o=iit”;
String dn = “uid=” + userName + “,” + base;
String ldapURL = “ldap://216.47.143.35:389/ou=people”;

authEnv.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.ldap.LdapCtxFactory”);
authEnv.put(Context.PROVIDER_URL, ldapURL);
authEnv.put(Context.SECURITY_AUTHENTICATION, “simple”);
authEnv.put(Context.SECURITY_PRINCIPAL, dn);
authEnv.put(Context.SECURITY_CREDENTIALS, password);
DirContext authContext = null;
try {
authContext = new InitialDirContext(authEnv);
System.out.println(“Authentication Success!”);
} catch (AuthenticationException authEx) {

authEx.printStackTrace();
System.out.println(“Authentication failed!”);

} catch (NamingException namEx) {
System.out.println(“Something went wrong!”);
namEx.printStackTrace();
}

Comment by admin
2008-10-14 08:25:52

This is untested, but try this:

try {
authContext = new InitialDirContext(authEnv);

String query = “uid=” + userName;
String attribute = “pdsRoles”;

‘eduPersonPrimaryAffiliation’
SearchControls ctrl = new SearchControls();
ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);
NamingEnumeration enumeration = authContext.search(“”, query, ctrl);
while (enumeration.hasMore()) {
SearchResult result = (SearchResult) enumeration.next();
Attributes attribs = result.getAttributes();
NamingEnumeration values = ((BasicAttribute) attribs.get(attribute)).getAll();
while (values.hasMore()) {
if (output.length() > 0) {
output.append(“|”);
}
output.append(values.next().toString());
}
}

Comment by Rakesh
2008-10-14 08:34:51

I am getting “javax.naming.NameNotFoundException: [LDAP: error code 32 – No Such Object]; remaining name ”” at line NamingEnumeration enumeration = authContext.search(“”, query, ctrl);
Any idea why i am getting this? I tried searching through other forums also but i couldn’t figure out the solution. Is it something to do with the authentication?

Comment by admin
2008-10-14 08:44:34

I am not sure off hand, although this line:
String dn = “uid=” + userName + “,” + base;
…looks suspicious to me.

(Comments wont nest below this level)
Comment by Rakesh
2008-10-14 08:48:42

Thanks a lot. Its very much appreciated. I have some thing to work on now. :)

 
Comment by Ankit Jain
2009-04-23 09:49:23

Hi Rakesh,

I am not a Java programmer but am trying to get the same thing accomplished using Oracle PL/SQL packages.
Somehow, my PL/SQL code is not authenticating me.

Can you send across your complete LDAP java code which I can compile and test to check that my LDAP server is working.
Essentially, all I need is “Authenticated” or “Failed” answer.

 
Comment by admin
2009-04-23 13:09:32

Ankit,

You can find the complete source code above, although it only demonstrates anonymous access.

 
 
 
 
 
 
 
Comment by Rakesh
2008-10-14 12:46:49

Hi,
I was able to get the Attribute that i wanted. I had to change my search criteria thats all. Thanks a lot for help.

Regards,
Rakesh

Comment by Yau
2009-04-17 00:21:36

Hi,

Actually i would like to get ALL the AD user list.
But, I’m not getting any result in the line -> “while (results != null && results.hasMoreElements()) {” . Any idea? Pls Help.

Hashtable env = new Hashtable();
String adminName = “CN=XX,CN=Users,DC=antipodes,DC=com”;
String adminPassword = “XXXXXXXX”;
String searchBase = “DC=abc,DC=com”;

String searchFilter = “(sAMAccountName=*)” ;
env.put(Context.INITIAL_CONTEXT_FACTORY,”com.sun.jndi.ldap.LdapCtxFactory”);
env.put(Context.SECURITY_AUTHENTICATION,”simple”);
env.put(Context.SECURITY_PRINCIPAL,adminName);
env.put(Context.SECURITY_CREDENTIALS,adminPassword);

//connect to my domain controller
env.put(Context.PROVIDER_URL, “ldap://abc.com.my:389/”);

try {
// Create the initial directory context
LdapContext ctx = new InitialLdapContext(env,null);
SearchControls searchCtls = new SearchControls();

String returnedAtts[]={“distinguishedname”};
searchCtls.setReturningAttributes(returnedAtts);

//Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

// Search for objects using the filter
NamingEnumeration results = ctx.search(searchBase, searchFilter, searchCtls);

while (results != null && results.hasMoreElements()) {
System.out.println(“>>> here….”);
SearchResult sr = (SearchResult)results.next();

//print out the name
System.out.println(“name: ” + sr.getName());

}

ctx.close();

}

 
 
Comment by Rakesh
2008-10-14 13:32:42

I had one more question about the LDAP Authentication. Is there a way to encrypt the Ldap authentication just like the way we encrypt the database connection. I couldn’t find the right resource on the net. It would be lovely if you can point me in the right direction.

Comment by admin
2008-10-14 13:46:35

I don’t know how to do this offhand, but have you tried Google?

 
 
Comment by paul
2008-12-23 06:53:49

Cheers, sorted out what could have been a long problem in minutes.

I dont deal with LDAP generally, just had to lend a hand in this instance.

 
Comment by suse
2009-06-01 03:21:15

Hi,
Can I know how to modify the cn attribute for all the ldap entries. Say I want to add suffix P to all the ldap entries in ldap.
Thanks

 
 
Comment by neel
2010-04-06 06:27:58

I am studying JNDI for application of a tool. I want this tool to return all names as well as user groups starting with ‘a’ from a domain say a.b.com. Can you please help?

Suggestions will be really appreciable.

Thanks and Advance

Comment by admin
2010-04-06 06:45:44

Neel,

Unfortunately, I don’t know how to do what you want offhand. Have you looked at a more complete LDAP reference, or tried Google for your specific task?

 
 
Comment by neel
2010-04-06 21:50:00

What if I want to retrieve the full list of users? Can you point to something useful?

 
Comment by neel
2010-04-06 21:58:03

Should this piece of code deliver what I am expecting?

Thanks a lot

 
Comment by lucentmind
2010-08-26 05:23:29

Thanks a lot for taking time to post this sample program!
One little hint that-for basic LDAP & JNDI related information refer
this

 
2011-01-10 13:28:14

This is really helpful to our current project. Thanks.

 
Comment by sal
2012-03-09 02:02:02

hi,
i’m new in ldap ,we had a project that needs opensso with ldap.
the main problem facing now is last 5 password won’t be same.if the user entered a password which is one of earlier one that user need to prompt him to enter new password.
if a user is inactive,then also a message to show him that he is inactive user,
another problem certain time opensso front page is showing on session time out etc,
please help me for these problem.

 
Comment by sonam
2012-12-10 04:59:42

hi,

I want to know how can I query LDAP server in order to retrieve the list of the usernames so that I can populate them in drop down list.

 

Sorry, the comment form is closed at this time.