Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
JavaRanch.com/granny.jsp
The moose likes Tomcat and the fly likes Windows Authentication Using Tomcat 5.0 Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Android Security Essentials Live Lessons this week in the Android forum!
JavaRanch » Java Forums » Products » Tomcat
Bookmark "Windows Authentication Using Tomcat 5.0" Watch "Windows Authentication Using Tomcat 5.0" New topic
Author

Windows Authentication Using Tomcat 5.0

visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi,

I am using Tomcat 5.0. I need to enable Windows authentication such that when the user types the url, he should prompted for the windows login. If the windows authentication fails, he should be redirected to the web application's login page. Please help me out. I am not using IIS.

Thanks,
Visu
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

Not sure what you mean by the "Windows" login.

Can you explain further?


Java API J2EE API Servlet Spec JSP Spec How to ask a question... Simple Servlet Examples jsonf
Stu Thompson
Hooplehead
Ranch Hand

Joined: Jun 14, 2006
Posts: 136
Hi Visu,

I am guessing you want to use users to authenticate via Tomcat's HTTP auth mechanism against a MS Windows Domain user database via LDAP/ActiveDirectory.

Check out http://tomcat.apache.org/tomcat-5.0-doc/realm-howto.html and pay attention to teh JNDIRealm stuff.

I've not done this personally, but this seems the correct path to follow.

Good luck!

Stu


"This is not to say that design is unnecessary. But after a certain point, design is just speculation." --Philip Chu
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi,

Thanks for the reply Thompson. My requirement is such that when a user types the url and clicks enter, the user should be allowed to enter the windows username and password. If that fails, the login page for the webapp should be displayed. I am very much confused about this. Please help me out.

Thanks in advance,
Visu
Stu Thompson
Hooplehead
Ranch Hand

Joined: Jun 14, 2006
Posts: 136
Hi Visu,

Hmmm...maybe your requirements are a little more complex than I understand or think reasonalbe.

That I suggest above would work like this:

1) User enters URL to your web app, www.stuisgreat.com in browser
2) Browser connects to Tomcat
3) Tomcat asks for user authentication
4) Browser prompts user for Windows user name and pwd in dialog box
5) Browser sends username and pwd to tomcat
6) Tomcat recieves user/pwd, looks at JNDI realm configuration
7) Tomcat asks the configured Windows Domain LDAP/ActiveDirectory server to authenticate user/pwd
8) Windows Domain LDAP/ActiveDirectory server responds 'user good'
9) Tomcat considers user authenticated, send requested page to browser.

Everything is good!

BUT, if the user enters a bad user/pwd then things will change:
8) Windows Domain LDAP/ActiveDirectory server responds 'user BAD'
9) Tomcat considers user not authenticated, goes back to step 3. If user fails to authenticate (give good user and password), then a HTTP 403 error page will be dispalyed. You can customize that if you like so it is pretty.

I hope this is what you are asking for.

It is not clear to me. I also hope you are not asking to authenticate agaist either the Tomcat user database or the Windows domain...that sounds tricky. If you are, well then may I suggest getting the above to work fist...that will be difficult enough.

Good luck!

Stu
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi,

Thanks for the reply Stu. Can you suggest me a starting point? I have gone through the documentation of tomcat. I was very much confused. How does the login box pop up after entering the url. I have tried it out in web.xml in security-constraints. But when i remove that and configure only the JNDIRealm in server.xml, the pop up is not being displayed and is directly redirected to the login page.

Thanks in advance,
Visu
Ulf Dittmer
Marshal

Joined: Mar 22, 2005
Posts: 41182
    
  45
You need to configure both web.xml and server.xml; one without the other is not sufficient.


Ping & DNS - my free Android networking tools app
Stu Thompson
Hooplehead
Ranch Hand

Joined: Jun 14, 2006
Posts: 136
Hi Visu,

You need to have both the web app's web.xml configured correctly (security-constraint and login-config) and the server.xml's realm entry. The web.xml is what will make tomcat ask the browser for authentication. Below the security-constraint ensure you have something like this:

The 'BASIC' part is what tells tomcat to use HTTP AUTH BASIC and makes the browser give a user a popup. Nice, clean and simple.

The server.xml configuration tells tomcat how to validate the username and password.

I took a look around "the google" but did not see any clear step-by-step instructions for doing what you whant to do. Sorry.

The steps you will want to follow, or at least I would do myself is:

1) get tomcat to ask user for user password with a browser dialog box. (This ensure that your webapp is secured)

2) configure the realm and get tomcat to use the user/pwd with the realm. If you have problems here, you might want to test against the native tomcat user database (./conf/tomcat-users.xml) Like I said, I've never autheticated against a JNDI realm...so I would only do that once I knew everything else was working.

3) test that the entire application works!

Stu
Stu Thompson
Hooplehead
Ranch Hand

Joined: Jun 14, 2006
Posts: 136
Ha!!! Ulf beat me by 1 minute. :p

Also, if you have problems with this specific issue again, please show us snippets from web.xml and server.xml.

Stu
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi,

Thanks Stu. It's working fine with the Tomcat User's database.
Here's the code snippet of server.xml.

<Realm className="org.apache.catalina.realm.JNDIRealm" debug="1"
connectionURL="ldap://192.168.110.2:389" roleBase="ou=myCompany,o=Users,dc=myCompany,dc=com"
roleName="Users"
roleSearch="(Users={0})"
roleSubtree="true"/>
Please help me out.

Thanks,
Visu
Stu Thompson
Hooplehead
Ranch Hand

Joined: Jun 14, 2006
Posts: 136
Hi Visu,

OK, now we are back to http://tomcat.apache.org/tomcat-5.0-doc/realm-howto.html#JNDIRealm This is good. (Your are also doing something now, JNDI Realm stuff, I never done.) From this link we see...

Quick Start

To set up Tomcat to use JNDIRealm, you will need to follow these steps:

1. Make sure your directory server is configured with a schema that matches the requirements listed above.
2. If required, configure a username and password for use by Tomcat, that has read only access to the information described above. (Tomcat will never attempt to modify this information.)
3. Place a copy of the JNDI driver you will be using (typically ldap.jar available with JNDI) inside the $CATALINA_HOME/server/lib directory (if you do not need it visible to web applications) or $CATALINA_HOME/common/lib (if it will be used both by Tomcat 5 and by your apps).
4. Set up a <Realm> element, as described below, in your $CATALINA_HOME/conf/server.xml file.
5. Restart Tomcat 5 if it is already running.


As for point 1, you will probably want to review the schema section with your domain administrator. I would not be surprised if he had to do something special, but not a big deal. (Like creating a folder on the AD structure and assigning users permissions to this folder.)

I would not worry about point 2 just yet...but review it for security reasons after everything is working.

Step 3 is obviously important. Have you a JNDI driver yet?

Step 4 is important too. Follow closely "Realm Element Attributes" with respect to your configuration. Also, I note that your configuration snippet for the JNDI real is the verbatim example. I suspect that it should reflect the realities of your Windows Domain/LDAP. Your domain administrator should be albe to help you there. (Or maybe anyone familular with how to get that information...it should be public and accessible by all users in your domain.)

OK, once you get the above done you will need to test and see what your logs report. When you get to the point where you cannot understand the logs (possibly with your domain adminstrator's help) then come back here and we can try to help more. Besure to include the realm configuration and the log file snippets.

Good luck!

Stu
[ November 08, 2006: Message edited by: Stu Thompson ]
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi,

Thanks Stu. When I tried out using Java, it's working fine. The authentication is done. But unable to do any operation on the directory. Here's the code snippet.

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://mycompany.com");
env.put(Context.PROVIDER_URL, "ldap://mycompany.com");
env.put(Context.SECURITY_PRINCIPAL, "domainName\\visu");
env.put(Context.SECURITY_CREDENTIALS, "XXXXXXX");
DirContext ctx = new InitialDirContext(env);

When configuring in JNDI Realm, it's connecting but unable to authenticate.
Here's the code snippet of web.xml.

<security-constraint>
<display-name>Example Security Constraint</display-name>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<!-- Define the context-relative URL(s) to be protected -->
<url-pattern>/*</url-pattern>
<!-- If you list http methods, only those methods are protected -->
<http-method>DELETE</http-method>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>PUT</http-method>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>org.apache.catalina.realm.JNDIRealm</realm-name>
</login-config>

server.xml

<Realm className="org.apache.catalina.realm.JNDIRealm" debug="99"
connectionURL="ldap://myCompany:389/dc=domainName,dc=com"
alternateURL="ldap://myCompany:389/dc=domainName,dc=com"
userBase="ou=domainName,dc=domainName,dc=com"
userSearch="(UID={0})"
userSubtree="true"
/>

Here's the error log.

2006-11-09 12:58:08 JNDIRealm[Catalina]: Connecting to URL ldap://myCompany:389/dc=domainName,dc=com
2006-11-09 12:58:08 JNDIRealm[Catalina]: Searching for domainName\visu
2006-11-09 12:58:08 JNDIRealm[Catalina]: base: ou=domainName,dc=domainName,dc=com filter: (UID=domainName\visu
)
2006-11-09 12:58:08 JNDIRealm[Catalina]: Exception performing authentication
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 'ou=domainName,dc=domainName,dc=com'
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3028)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2934)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2740)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1811)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1734)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:368)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:328)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:313)
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:238)
at org.apache.catalina.realm.JNDIRealm.getUserBySearch(JNDIRealm.java:1047)
at org.apache.catalina.realm.JNDIRealm.getUser(JNDIRealm.java:940)
at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:889)
at org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:782)
at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(BasicAuthenticator.java:129)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:793)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:702)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:571)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:644)
at java.lang.Thread.run(Thread.java:534)

I couldn't get appropriate feedback from my admin. Where's the file located that contains the Active Directory usernames and what will be name of it. We are using Windows 2003.

Thanks in advance,
Visu
Stu Thompson
Hooplehead
Ranch Hand

Joined: Jun 14, 2006
Posts: 136
Hi Visu,

Ah, those admin types are always so frield and helpful, eh? (Sarcasim!) The stories I could tell you...

Anyway, when I see this snippet from your logs:

..it looks to me like Tomcat is not succesfully connecting to the domain. That means it has not even had a chance to validate the passed username and password.

I am 99.999% certain you will have to get that server.xml snippet configured correctly before proceeding.



E.g.: connectionURL should, I would think, point to your domain server. dc would be your domain name.

There is a M$ tool I used a few years ago that allowed one to explore a domain's AD structure and get important details. I forget the name but am pretty sure it is in something like the "Windows Server Administration Pack" (or similar). I don't have time today to go looking it here...but maybe tomorrow or monday.

Sorry I can't get more to you today...

Stu
[ November 09, 2006: Message edited by: Stu Thompson ]
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi,

Anyway thanks Stu. My current requirement has changed. Due to some security issues, I was asked to get openldap and connect to ADS using openldap. Currently I am working on it and will let you know.

Thanks,
Visu
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi Stu,

The requirements have changed again. Using IIS, I am supposed to do the Windows Authentication.But I have done the necessary work on LDAP. Inorder to connect to an Active Directory server, a username and password is required, which is configured in the slapd.conf file. Due to security reasons anonymous access is disabled on ADS. Once we connect to the ADS, we can query the information. An user information is stored in the format:

dc:myCompany
dc:com
o:myCompany
ou:department
sn: sur name
uid : user id
email : mail address

We have to specify the search string as userSearch : {uid(0)}. This carries the username to the ADS and if it exists, then validates the password.

If we use OpenLDAP as a proxy server, we have to specify an entry in the ADS ldap-proxy and we will have to map the attributes to the ADS. Using slurpd.exe, we can replicate the data in ADS to OpenLDAP server and using slapd.exe, we can add entries to the OpenLDAP server.

Currently, I am working with configuring IIS with tomcat, enable the windows authentication in IIS, and get the username using the request header and if the windows authentication fails, forward to another page. If we have any useful links on this, please let me know.

Thanks in advance,
Visu
Stu Thompson
Hooplehead
Ranch Hand

Joined: Jun 14, 2006
Posts: 136
Hi Visu,

Wow. That sounds more complex than I would have expected, but like mentioned earlier...I have not actually implemented this myself therefor my opinion is suspect.

E.g.: I would have expected that the candidate user's login credentials would be used to access the ldap server or use an account setup for specially for tomcat rather than anon access. Maybe I just don't understand something here but I would think you could do this in a secure manner. It happens

Also, using IIS as a proxy seems unnecessary...unless that is it is there already for other purposes.

Question: Are you administrator's hostile towards non-MS platforms?

Regardless, let us know how you get on and what you learn. This is all interesting stuff!

Stu
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi Stu,

I have encountered a peculiar problem. I am able to retrieve the username, domain name using the following code directly on tomcat.

String auth = request.getHeader("Authorization");
if (auth == null)
{
response.setStatus(response.SC_UNAUTHORIZED);
response.setHeader("WWW-Authenticate", "NTLM");
response.flushBuffer();
return;
}
if (auth.startsWith("NTLM "))
{
byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
int off = 0, length, offset;
if (msg[8] == 1)
{
byte z = 0;
byte[] msg1 = {(byte)'N', (byte)'T', (byte)'L', (byte)'M', (byte)'S', (byte)'S', (byte)'P',
z,(byte)2, z, z, z, z, z, z, z,(byte)40, z, z, z,
(byte)1, (byte)130, z, z,z, (byte)2, (byte)2,
(byte)2, z, z, z, z, z, z, z, z, z, z, z, z};
response.setHeader("WWW-Authenticate", "NTLM " +
new sun.misc.BASE64Encoder().encodeBuffer(msg1));
response.sendError(response.SC_UNAUTHORIZED);
return;
}
else if (msg[8] == 3)
{
off = 30;

length = msg[off+17]*256 + msg[off+16];
offset = msg[off+19]*256 + msg[off+18];
String remoteHost = new String(msg, offset, length);

length = msg[off+1]*256 + msg[off];
offset = msg[off+3]*256 + msg[off+2];
String domain = new String(msg, offset, length);

length = msg[off+9]*256 + msg[off+8];
offset = msg[off+11]*256 + msg[off+10];
String username = new String(msg, offset, length);

out.println("Username:"+username+"<BR>");
out.println("RemoteHost:"+remoteHost+"<BR>");
out.println("Domain:"+domain+"<BR>");
}
}

But when I am trying to access the same thing through IIS, i am getting null values. Please help me out.

Thanks in advance,
Visu
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi Stu,

I forgot one more thing. Can we map names to our applications. For e.g. http://127.0.0.1:8080/jsp-examples to http://home.abc.com,
http://127.0.0.1:8080/servlets-examples to http://home.xyz.com

Thanks in advance,
Visu
Ben Souther
Sheriff

Joined: Dec 11, 2004
Posts: 13410

visu Nekk
Javaranch tip:

If you are going to post more than a line or two of your code, wrap that
code in a set of UBB Code tags.
Doing so will help to preserve your code's indenting, making it easier to read.
If it is easier to read, more people will actaully read it and you will
stand a better chance of getting help with your question.
See UseCodeTags for more
help with UBB code tags.
visu Nekk
Ranch Hand

Joined: Sep 06, 2005
Posts: 122
Hi Stu,

I have a problem with request.getRemoteUser(). It's not returning anything not even null. I have tried all the possibilities. in jk2.properties, i placed an entry tomcatAuthentication=false. I even tried request.tomcatAuthentication=false. I have checked Anonymous Access and Integrated Windows Authentication in IIS. I did this because I don't want a login box to popup, but to retrieve the username using request.getRemoteUser(). Please help me out if I am missing out anything.

Thanks in advance,
Visu
suneel kumar
Ranch Hand

Joined: Jan 08, 2007
Posts: 46
[ UD: Please don't post the same question multiple times. Since this is an old thread, let's continue the discussion in this duplicate post. ]
[ February 29, 2008: Message edited by: Ulf Dittmer ]
Lars Vegas
Greenhorn

Joined: Dec 04, 2001
Posts: 27
Hi Visu,
did you ever figure out how it worked? I'm facing the same problem. request.getRemoteUser is always null but I desperately need it.
Lars
David Lee Lambert
Greenhorn

Joined: Oct 02, 2006
Posts: 7
I'm struggling with what may be a similar issue.

I've developed a web-application and tested it on Tomcat 5.5 on my workstation. Instead of adding a <Realm/> element to server.xml, I created the file META-INF/context.xml, with a <Realm/> element as follows:



This works fine on my workstation: any user can authenticate to that instance using their AD username and password. However, for production use, I tried to deploy it to a Tomcat 5.0.28 server that's already running another web-application. It appears that the realm definition in the webapp isn't being used: I can only log in with the admin username and password that are used to access the /manager application, and that user doesn't belong to any of the roles that are used to control access to my application.

Does anyone know if Tomcat 5.0 didn't support META-INF/context.xml, or if additional configuration needs to be done to support it?
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Windows Authentication Using Tomcat 5.0
 
Similar Threads
JSP and Active Directory Integration
Get Intranet login username
Change password windows form control using LDAP in tomcat 5.0.
Servlet issue
pageContext.exception is not executing