Thursday, March 15, 2007

Sun Java System Application Server 9.x (glassfish) External JNDI LDAP Resource Part II

In my recent blog entry on configuring an external JNDI LDAP entry, I showed how to connect to an LDAP server as a JNDI reference. This assumes that the LDAP server is on the local machine and that it allows anonymous authentication. Usually this is not the case. I will cover how to use a login to an LDAP server which requires a little more configuration.

Prerequisites:
  • A working LDAP server
  • A login which can browse the directory tree
Instructions:

Please follow the directions in my previous blog entry to set up the basic external JNDI resource. The Sun Java System Application Server 9.1 Administration Guide is incorrect on how to set the properties. It refers to using some properties that are defined for LDAP like PROVIDER-URL. Unfortunately, to use them you would need to prefix them with the appropriate class. So we will use an alternate tack and use them by their fully qualified names. Add the following properties to the entry.

PROVIDER-URL:
java.naming.provider.url

SECURITY_PRINCIPAL:
java.naming.security.principal

SECURITY_AUTHENTICATION:

java.naming.security.authentication

SECURITY_CREDENTIALS:

java.naming.security.credentials

Since we have the fully qualified names, we can use them to set the properties for our external JNDI resource. See the image below.


Once you have the properties set and saved, you will have a complete external JNDI LDAP connection.

Congratulations!

10 comments :

Joshi said...

Nice article. I followed your steps but I don't see my external resource (ldap/uOneLdap) listed under Application Server => JNDI Browser.

I do see external resource listed under netbeans IDE => Services => GlassFishV2=>Resources=>JNDI=>External Resources=>ldap/uOneLdap and C:\Program Files\GlassfishV2\domains\domain1\config\domain.xml file.

When I try to use as
@Resource (Name ="ldap/uOneLdap")
private LdapContext ctx;

I get following exception:
AM0006: JMS Destination object not found: ldap/uOneLdap
javax.naming.NameNotFoundException
javax.naming.NameNotFoundException
at com.sun.enterprise.naming.TransientContext.resolveContext(TransientContext.java:268)
at com.sun.enterprise.naming.TransientContext.lookup(TransientContext.java:191)
at com.sun.enterprise.naming.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:74)

John Yeary said...

Here are some suggestions:

1. Did you check to make sure that the external resource was available?
2. If the resource was not available, not started when the server was configured, you will need to restart the domain.

Let me know if that helps.

Joshi said...

I think I found the problem. As you said, resource was not available is correct.
This is a remote ldap server and doesn't accept anonymous login. when I enter external resource without properties, it was not available but when I added properties, it is displayed in JNDI browser.

This is helping a lot as I don't have to hardcode any ldap properties into the code.

Thx.

John Yeary said...

Awesome! I am glad that I could help.

I am glad that worked. I encounter the same issue if I forget to make sure that the resource is available before I set it up in Glassfish.

Joshi said...

Interesting finding:
When I use external resource to search ldap, it performs one additional search (search number 19).

e.g Here is ldap snoop using Wireshark

|Time | 10.239.69.229 | 208.248.239.75 |
|7.385 | searchRequest(19) " |LDAP: searchRequest(19) "ou=ILN1,o=mycompany.com" baseObject
| |(3781) ------------------> (389) |
|7.387 | searchResEntry(19) |LDAP: searchResEntry(19) "ou=ILN1,o=mycompany.com"
| |(3781) <------------------ (389) |
|7.387 | searchResDone(19) |LDAP: searchResDone(19)
| |(3781) <------------------ (389) |
|7.387 | searchRequest(20) " |LDAP: searchRequest(20) "ou=ILN1,o=mycompany.com" wholeSubtree
| |(3781) ------------------> (389) |
|7.389 | searchResEntry(20) |LDAP: searchResEntry(20) "uniqueidentifier=100307225029593ff848d4d4c,ou=subscribers,ou=GlenAllen,ou=ILN1,o=mycompany.com"
| |(3781) <------------------ (389) |
|7.389 | searchResDone(20) |LDAP: searchResDone(20)
| |(3781) <------------------ (389) |
|44.549 | 2288 > 24800 [PSH, |synergy: 2288 > 24800 [PSH, ACK] Seq=11448 Ack=16898 Win=64765 Len=8

Here 2nd search is performed by my code but don't know who does the first search?

This is how I am using external resource "ldap/uOneLdap" in code.

Properties prop = System.getProperties();
InitialContext ctx = new InitialContext();
ldap = (DirContext) ctx.lookup("ldap/uOneLdap");
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = {"mail", "ummsghost", "cn"};
controls.setReturningAttributes(attrIDs);
String filter = "(telephonenumber=" + subscriber + ")";
NamingEnumeration ne = ldap.search("", filter, controls);

Earlier I was creating instance of DirectoryContext and passing a hashtable with all context enviorment variables and only one search was performed.

Do you know what could be causing this?

John Yeary said...

The baseObject (BaseDN) is being retrieved first on the initial search. Then it performs a search on the sub-tree from the returned result.

You would have to look at your LDAP server documentation on the specifics, but the searchRequest is the heart of the LDAP protocol. Here is a link to the Apache DS ASN Tree which you can follow the process from your snoop session.

Apache DS LDAP ASN Syntax

Jeff said...

I also tried it with Windows Active Directory external LDAP. I succeed in browsing it in JNDI tree. But as soon as I make search or call any other DirContext methods I get the following exception:
javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001CD, problem 2001 (NO_OBJECT), data 0, best match of: 'DC=mydomain,DC=local'

John Yeary said...

I don't use Active Directory so I am not able to tell you what the majority of the message means, but the information you provided does not look complete. It would help to have more of the exception, and what you were doing.

A quick check on Google has a number of explanations of LDAP: error code 32. A number of them are missing something from their query string.

Jeff said...

The rest of message is stack trace and does not carry any useful info. I can use LDAP while I create InitialDirContext with environment variables. But with JNDI lookup although Glassfish instantiates DirContext neither of the methods are work.

John Yeary said...

I really don't have enough information to really be of help. You indicated that the stack trace does not contain any valuable information.

I don't use Active Directory so I can't really try to reproduce anything. Not to mention I don't have any code to examine.

Without any additional information, I can't help you.

I have used this technique for a number of production systems so I know it works.

There is one link you may check out:

http://forum.springsource.org/showthread.php?71203-Active-Directory-LDAP-Authentication-LDAP-Error-32

It suggests removing the baseDN.

Popular Posts