wood burning stoves 2.0*
The moose likes Java in General and the fly likes Connecting to Active Directory using LDAP Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Java 8 in Action this week in the Java 8 forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Connecting to Active Directory using LDAP" Watch "Connecting to Active Directory using LDAP" New topic
Author

Connecting to Active Directory using LDAP

Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
I have been trying to use LDAP authentication for connecting to the active directory, and I'm having some problems. I have a few questions.

First:
I can set up a test to use for the username and password, but I want to use the ones in the AD instead, not hard code them in.
Second:
I can't even test it yet because I'm getting this error:
2:10:33,870 INFO [STDOUT] fetch error: javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece; remaining name 'cn=admin,cn=users,dc=ssc,dc=mycompany,dc=com'


The method it is failing at looks like this:

public Attributes fetch(String username) {
Attributes attributes = null;
try {
System.out.println("fetching: " + username);
DirContext o = (DirContext) ldapContext.lookup("cn=" + username
+ baseName);
System.out.println("search done\n");
attributes = o.getAttributes("");
for (NamingEnumeration<?> ae = attributes.getAll(); ae
.hasMoreElements() {
Attribute attr = (Attribute) ae.next();
String attrId = attr.getID();
for (NamingEnumeration<?> vals = attr.getAll(); vals.hasMore() {
String thing = vals.next().toString();
System.out.println(attrId + ": " + thing);
}
}
} catch (Exception e) {
System.out.println(" fetch error: " + e);
System.exit(-1);
}
return attributes;
}

I debugged and the error was when I declared a DirContext.

Has anyone seen this problem before?
[ August 29, 2008: Message edited by: Heather Rose ]
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
The answer is in the error message. You server is set up so that you have to log in (bind) to the server before you can read data from it. The normal way to authenticate a user using LDAP is to try to bind to the server as that user. If the bind fails then the user name and/or password are incorrect.


Joanne
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
So, I'm a little confused about the binding. I have to bind every single user? Or just an admin?
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
What are you actually trying to do ?
Are you trying to authenticate as a particular user or get a list of all the users in AD ? If the latter, what do you intend to do with this list ?
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
Well, what I am trying to do is just connect to the AD using LDAP. I just want to be able to login with one of the users from the AD. I'm going to be using the database for authentication and security, but I just want to use LDAP to connect. I'm sure I'm overcomplicating this, though.

I have changed some things in my code, as I found a kind of tutorial. This is what I have now. But there are no errors, but it still doesn't let me log in using a user from the AD.


public class LDAPAuth {

public Hashtable<String, String> env = null;

public Control[] connCtls = null;
Context ctx;
DirContext dirContext;
public LdapContext ldapContext = null;
String baseName = ",cn=users,dc=ssc,dc=mycompany,dc=com";
String modelUsername = "template";
String serverIP = "ssc-dc-01.ssc.mycompany.com";

public LDAPAuth(String ldapurl) {

ldapurl = "ldap://" + serverIP + ":389";

try {
env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.PROVIDER_URL, ldapurl);
env.put(Context.SECURITY_PRINCIPAL, "cn=Heather" + baseName);
env.put(Context.SECURITY_CREDENTIALS, "mysecret" + baseName);
env.put(Context.SECURITY_PROTOCOL, "ssl");
ctx = new InitialContext(env);

} catch (Exception e) {
System.out.println(" bind error: " + e);
e.printStackTrace();
}

try {
ldapContext = new InitialLdapContext(env, connCtls);
} catch (AuthenticationException e) {
System.out.println("Authentication exception " + e);
} catch (NamingException e) {
System.out.println("Naming exception " + e);
}
}

public Attributes fetch(String username) {
Attributes attributes = null;
try {
System.out.println("fetching: " + username);
Object obj = ctx.lookup("cn=" + username
+ baseName);
System.out.println("cn=" + username + baseName + "is bound to: " + obj);
//attributes = obj.getAttributes("");
for (NamingEnumeration<?> ae = attributes.getAll(); ae
.hasMoreElements() {
Attribute attr = (Attribute) ae.next();
String attrId = attr.getID();
for (NamingEnumeration<?> vals = attr.getAll(); vals.hasMore() {
String value = vals.next().toString();
System.out.println(attrId + ": " + value);
}
}
} catch (NamingException e) {
System.out.println(" Problem looking up " + username + baseName + ". " + e);
}
return attributes;
}

public void finito() {
try {
ldapContext.close();
System.out.println("Context is closed");
} catch (NamingException e) {
System.out.println("Context close failure " + e);
}
}

}


I have another class that I call the fetch method right before it returns "logged in" true and that's how it gets here.
[ August 29, 2008: Message edited by: Heather Rose ]
Tom Ethens
Greenhorn

Joined: Jun 10, 2008
Posts: 16
What is the exact error message that you get?

Regards,
Tom
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
Actually, right now, I don't get any error message. It goes completely through.

No matter what it fails. The correct password fails and the wrong password fails. From the AD anyway.

If I try to login through the database instead (as admin)it'll work fine. But I can't log in through AD. I want to completely change my app so that it will always use what's in the AD so that we know who is logging in. As of right now, we only have a default few users and passwords in the DB.
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
Both right and wrong passwords will get the correct 'wrong password' message. No error. Both of them are correctly caught, even though one of them is supposed to be the correct password and I should be able to log in.
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
One possible problem is that you have set your security protocol to SSL, but you are trying to connect to the non-SSL port.
If you are using SSL, try changing the port to 636.
If you are not using SSL, try taking out the line
env.put(Context.SECURITY_PROTOCOL, "ssl");
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
That didn't change anything. It's still doing what I had before, and I've switched some code around and changed the order of some things. I made it much more simple than I had it before (as I had a few more methods than I do now). I still get the same 'non-error' though.

Another issue I am having is that I can't debug in Eclipse, it's kind of weird. Whenever I debug, it just gives me an error message (not even in the console, just on the Debug screen)

It says, "Source not found for XMLEntityScanner.load(int, boolean) line: not available". And if I step over it, I just get a BUNCH of the same type of errors.

Any suggestions on any one of these issues? I'm starting to get a little frustrated with this issue.
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
You could try using an LDAP browser like Softerra. If you can log on with that then we know it's a problem with your code. If you can't then it's a problem with AD.
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
I downloaded Softerra, but I don't see my database anywhere. Should I add it somewhere? Also, I don't know how to log in? When I add my AD or my database, it will prompt me, is this correct?
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
Click on File/New Profile and then add the details asked for by the wizard. This will include a username and password.
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
Alright, I'm not able to log in to the AD either. So, this is an AD problem? What can I do to fix this?
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
The code I have now is this:

Hashtable<String, String> env = null;
username = "hkrose";
String password = "secret";
String baseName = ",dc=ssc,dc=mycompany,dc=com";
String serverIP = "ssc-dc-01.ssc.mycompany.com";
String ldapurl = "ldap://" + serverIP + ":389";

env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.PROVIDER_URL, ldapurl);
env.put(Context.SECURITY_PRINCIPAL, "cn=" + username
+ ",cn=users" + baseName);
env.put(Context.SECURITY_CREDENTIALS, password);
// env.put(Context.SECURITY_PROTOCOL, "ssl");


That's all. I changed some of my methods to make it a little more simple. I should have access to the active directory, but for some reason, I can't log in. How do I go about fixing this? I want ANY user from ANY group to be able to log in. Obviously, their permissions are different depending on what group they are in.

To be, everything here looks right. Meaning, it's the AD. Now, I have just learned what AD was a few days ago (When I first made this post) so I'm not sure if there are settings I need to change for this to work.

Anyone have any direction?

[ August 29, 2008: Message edited by: Heather Rose ]
[ August 29, 2008: Message edited by: Heather Rose ]
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
It's been a few more days and I have found out a little more about what exactly the problem is. There's not a problem in my code, nor in the AD. I can get the DN from the AD. But since anonymous binds are restricted from AD, someone has to be logged in to get this information. Now, I have learned a little more about both, as I have done the tutorial from Sun on JNDI. Which was extremely helpful.

What I am facing now, is that I have to set up the jboss-web.xml file, or so I heard. Can anyone give me some more information on this topic? I seem to be getting closer. It feels like I am very close.

Thanks everyone for your help and input.
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
I know no one has been replying, but that's not going to stop me from asking for more help. I have been working on this problem for quite some time now. I now know I was missing a bind when I kept receiving that error. Does anyone know how to correctly bind to the AD using LDAP? Please, someone help me? I have looked this up and tried many things. Nothing seems to be working.

Thanks if anyone replies.
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
It's probably best if you forget about JBoss and whatever else is involved in your system and just write a simple program based on the JNDI tutorial examples that allows you to bind to the AD server. The program shown here is probably a good place to start. If you click on the 'following example' link it will give you the full source code so you don't have top worry about typos. Just change the server, user name and password and then run it.
If that doesn't work, post any error messages you get.
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
This tutorial is actually the one I used to get started. Along with other posts on the web. Now, it seems that my issue is the binding.


This is what I have for the LDAP class.


private transient String userLogin;
private transient String userPassword;
User user;

Hashtable<String, String> envGC = new Hashtable<String, String>();
Hashtable<String, String> envDC = new Hashtable<String, String>();

public LDAPCrap() throws NamingException {

// envGC = new Hashtable();
// envDC = new Hashtable();

String urlGC = "ldap://mycompany.com:3268";
String urlDC = "ldap://mycompany:389";

envGC.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
envDC.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");

envGC.put(Context.PROVIDER_URL, urlGC);
envDC.put(Context.PROVIDER_URL, urlDC);
}

public void setUserLogin(String uid) {
this.userLogin = uid;
}

public void setUserPass(String password) {
this.userPassword = password;
}

public boolean isAuth() throws NamingException {

DirContext ctxGC = new InitialDirContext(envGC);
DirContext ctxDC = new InitialDirContext(envDC);

boolean auth = false;
try {

ctxDC.getNameInNamespace();
ctxGC.getNameInNamespace();

// String userDN = getDN(this.userLogin);

envGC.put(Context.SECURITY_AUTHENTICATION, "simple");
envGC.put(Context.SECURITY_PRINCIPAL,
"cn=Username,cn=Users,dc=ssc,dc=mycompany,dc=com");
// envGC.put(Context.SECURITY_PRINCIPAL, "cn=" + this.userLogin
// + "cn=Users,dc=ssc,dc=mycompany,dc=com");
envGC.put(Context.SECURITY_CREDENTIALS, this.userPassword);

envDC.put(Context.SECURITY_AUTHENTICATION, "simple");
envDC.put(Context.SECURITY_PRINCIPAL,
"cn=AUsername,cn=Users,dc=ssc,dc=mycompany,dc=com");
// envDC.put(Context.SECURITY_PRINCIPAL, "cn=" + this.userLogin
// + "cn=Users,dc=ssc,dc=mycompany,dc=com");
envDC.put(Context.SECURITY_CREDENTIALS, "password");

envDC.put(Context.REFERRAL, "follow");
envGC.put(Context.REFERRAL, "follow");

auth = true;

} catch (AuthenticationException e) {

auth = false;
} catch (NamingException e) {
auth = false;
System.out.println("Error in Authentication " + e);
}

String base = "";
int totalResults = 0;
String filter = "(objectclass=*)";

ctxDC.bind(userLogin, user);
ctxGC.bind(userLogin, user);

SearchControls controls = new SearchControls();

// may be a scope change
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

NamingEnumeration<?> answer = ctxGC.search(base, filter, controls);

// ... process attributes ...

while (answer.hasMoreElements()) {

SearchResult sr = (SearchResult) answer.next();
Attributes attrs = sr.getAttributes();

System.out.println("RootDSE: " + sr.getName());

if (attrs != null) {

try {

System.out.println(" Naming Context: "
+ attrs.get("defaultNamingContext").get());

System.out.println(" Schema Context: "
+ attrs.get("schemaNamingContext").get());

System.out.println(" DNS: "
+ attrs.get("dnsHostName").get());

System.out.println(" Server Name: "
+ attrs.get("serverName").get());

System.out
.println(" name(GC) Context: "

+ attrs.get("givenName").get() + ""
+ attrs.get("sn").get());

System.out.println(" mail(GC) Context: "
+ attrs.get("mail").get());

} catch (NullPointerException e) {
System.err
.println("Problem listing attributes from Global Catalog: "
+ e);
}
}

Attributes DCattrs = ctxDC.getAttributes(sr.getName());
try {
System.out.println(" Web(DC_):"
+ DCattrs.get("wWWHomePage").getID());
System.out.println(" Fax(DC):"
+ DCattrs.get("facsimileTelphoneNumber").getID());
// } catch (NamingException e) {
//
// System.out.println("Problem retrieving RootDSE: " + e);

} catch (NullPointerException e) {
System.err.println("Problem listing attributes from Domain "
+ " Controller:" + e);
}

try {
System.out.println("Total Results:" + totalResults);
ctxDC.unbind(userLogin);
ctxGC.unbind(userLogin);
ctxDC.close();
ctxGC.close();
} catch (Exception e) {
System.out.println("FAILED: " + e.getLocalizedMessage());

}

}
return (auth);
}



And the error messages I have been getting look like this:



java.lang.IllegalArgumentException: cannot bind null object with no attributes
at com.sun.jndi.ldap.LdapCtx.c_bind(Unknown Source)
at com.sun.jndi.ldap.LdapCtx.c_bind(Unknown Source)
at com.sun.jndi.toolkit.ctx.ComponentContext.p_bind(Unknown Source)
at com.sun.jndi.toolkit.ctx.PartialCompositeContext.bind(Unknown Source)
at com.sun.jndi.toolkit.ctx.PartialCompositeContext.bind(Unknown Source)
at javax.naming.InitialContext.bind(Unknown Source)
at LDAPCrap.isAuth(LDAPCrap.java:91)
at LoginServlet.doGet(LoginServlet.java:48)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
at java.lang.Thread.run(Unknown Source)
[ September 08, 2008: Message edited by: Heather Rose ]
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 18139
    
  39

This tutorial is actually the one I used to get started. Along with other posts on the web. Now, it seems that my issue is the binding.


Well, good luck. I had to do a JNDI connection to Active Directory a few years ago, and it was a pain in the arse. The API was incredibly particular, one way worked for one attribute, but not another. Ordering was also important.

In the end, I comb through many many code solutions, for more than a week. None of them had a completely working example. Mixing and matching different solutions. And lots of trial and error before I got everything right.


In retrospect, I wished that I saved a copy of the library. This was for my previous company, so no longer have access to the CVS. Oh well, hopefully, I won't have to do it again.

Anyway, I don't really have a solution, except to say don't give up -- it really was a pain in the arse, but it does work.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
Thanks for the encouragement. It seems I have explored the entire internet. But, to no avail...

Well, I'll keep trying, and I'll post the completed solution here so some other poor soul won't have to go through the same things we did.

Thanks!
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
The only thing I can suggest once again is that you start with a simple test program that you run from the command line and then build up from there. The less code you have, the less places there are for errors to occur. The following program works for me (obviously with different server, username and password).
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
So, I have used the code you have provided, and it seems I'm still doing something wrong.





I have added the search just to see if it would print anything out ,and I receive this error.

ERROR [STDERR] javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-031001A8, problem 2001 (NO_OBJECT), data 0, best match of:
''


If I don't put any of this in there at all, and just run with the bind successful in the try, obviously, I don't get any error. I needed somethign to work with, that's why I added it.
Any ideas?
[ September 09, 2008: Message edited by: Heather Rose ]
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54


Now, this right here seems kind of odd to me, beacuse you create your LdapContext, but you never bind it, nor call it at all. Then it just says Bind successful. Why is this the only thing in the try?

[ September 09, 2008: Message edited by: Heather Rose ]
[ September 09, 2008: Message edited by: Heather Rose ]
Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3169
    
  10
Originally posted by Heather Rose:
Now, this right here seems kind of odd to me, beacuse you create your LdapContext, but you never bind it, nor call it at all. Then it just says Bind successful. Why is this the only thing in the try?


By including the SECURITY_PRINCIPAL and SECURITY_CREDENTIALS fields in the environment that you pass to the constructor, the bind will be done automatically.
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
Alright, so I got Active directory to work with a sample project, but I can't get it to work when I integrate it with my own project. I didn't use hardly anything, which was strange to me. In my sample, this is what I have:
In the JSP:
I have 2 input fields for username and password. 'user', 'pwd'.

Now, in my servet, I have:


That's all that's in the post method of the servlet.

I have a Report class that is also using some logic:




That was in the post. This is in a method I created called processLogin



I also had to use the javax.servlet.jar and the ejb-jar.xml for this application.

In the web.xml I needed to add an ejb-ref tag:




Also adding in the jboss.xml file the security domain, which should already be there.


SOMEHOW, this worked. Now, I'm not exactly sure how, but it did. Now, when I added all this to my project, nothing happens. No change, actually Eclipse doesn't even recognize any of it.

I debug my code (after I took out all the old stuff and re-built), and it's actually READING THE OLD CODE. I don't even know how that worked. I closed out my other sample project, built the project, and restarted the server. I ran, and that's what happens.

Interesting... really..

Anyone have any ideas why this is happening? So I can start on the real problem at hand? I have been working on this for SOOO long!!!
[ September 19, 2008: Message edited by: Heather Rose ]
Heather Rose
Ranch Hand

Joined: Aug 25, 2008
Posts: 54
Ok, I found out how to connect to active directory if anyone is still interested in this.

In my login method, I just added these couple of lines. I was so upset when it actually worked! It was so easy!


Just so.... easy. Well, it worked for me. I had to change some things in the config files as it says above, but this makes it so where you don't have to hardcode in a username and password and it's EXTREMELY hard to break. The other code with the security credentials was too easy to crack so we couldn't use that for our project.


Well, hope this helps someone.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 36598
    
  16
Your persistence has paid off ( ) well done.
Forrest Ham
Greenhorn

Joined: Sep 12, 2008
Posts: 1
grats.. having just switched to a team that is java centric vs C# I may need this information one day. Which is why this thread piqued my interest.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 36598
    
  16
And welcome to JavaRanch, Bob Marley
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Connecting to Active Directory using LDAP
 
Similar Threads
Problem with Return type for LDAP Search
LDAP and NamingEnumeration
Ldap newbie
com.sun.net.ssl.internal.ssl.Provider()
LDAP: error