Allowing anonymous browsing in addition to NTLM

May 31, 2010 at 7:54 AM

Hi,

Thanks for the library. I haven't tried it yet, but it seems a nice fit to what I need.

My questions is, I want to use SPNEGO (either NTLM or Kerberos, but preferrably NTLM because of the Kerberos limitations and configuration requirements) to get to who is browsing the web, but I don't want any authorization.

I mean, I want the user to be able to browse the web anonymously if there can't be NTLM authentication, without showing him any Unauthorized error pages. But if the browser was capable of providing a credential, I can use it to provide extended functionality.

So, basically I want request.getRemoteUser() to return null is there's no authenticated user on the other end, and contain the usernam if there is.

Is this possible?

Coordinator
May 31, 2010 at 3:14 PM

Hello,

To have authentication, you must define a security constraint in the file web.xml. So, the browser  sends the information in the header Authorization. If the browser cannot send something, it prints the page send by Tomcat. If all of your users have an account in Active Directory, you can give the authorizations to the group Everyone or Authenticated Users.

Are your servers on UNIX? On Windows? Where are the accounts of your users?

Dominique Guerin

Jun 1, 2010 at 7:19 AM

Thanks for your reply.

Our currently targeted servers are Windows, but Linux servers should be supported later.

Here's the full story: My product has an internal users database. Most of the customers use the internal database, and use a form to authenticate. It is required for us to enable single-sign-on for the application if there is an Active Directory in the network, and users have logged in to the domain, and if the customer has enabled it in the application config.

The application has a large and complex User and Permissions model, so I need to map domain accounts to my own user accounts anyway. And it should not get in the way of a client system outside the domain / outside the network. So, I want to put a "Domain Account" attribute in the users profile, so that the network admin can fill the attributes (like setting "DOMAIN\Someuser" for our "someuser" in our own database).

What I've reached up to now, is to put a single protected page for single-sign-on, and if the user could browse to it, use request.getRemoteUser() and fill-in the session with my own authentication data. If not, redirect the client to forms-based login page.

I'm currently struggling to setup the example to work. Here's a few points that I've noticed that you might want to fix:

  • in the trunk-dll-20022010\dll\vc90 directory, the 64-bit DLL is named SSPAuthentification64x.dll, but I noticed the application looks for the file named SSPAuthentificationx64.dll. (x64 versus 64x). Renaming the file fixed the problem. The other version (in PLatformSDK2003x64 folder) is correct.
  • Trying in 64bit Windows 7 (my own PC), Tomcat couls start alright, loading the Valve and DLL. But Tomcat to crashs unexpectedly (without any exception or log) when the authentication needed to be performed. (as soon as a request comes to a protected page). I figured it can be a 64-bit bug, so I tried on an x86 windows XP and it works. Not sure it's because of Win7 or x64.
  • I haven't been able to successfully authenticate from a remote PC. When I start the Tomcat, openning the browser from the local machine works pretty well, but from a remote computer it can't authenticate. (there are 3 request-response pairs with Negotiate each time, but the server doesn't seem to accept my credentials). All PCs are members of the domain. I'm trying a few things to see what might be wrong, I will probably ask another question if I couldn't get it to work.
Coordinator
Jun 1, 2010 at 7:51 PM

Hello,

Thank you for the remarks.  I will verify the name of the dll in the next version.

I tested the x64 version on Windows 2003. I will test again on 2003, 2008 and 2008 R2.

You can also use the version with tcp. It works on x86 and x64. I do not use native code. I wrote the service in c#.

All PCs are members of AD. Are your accounts also in AD? Is tomcat running as a service? Which account runs tomcat?( System, Network service ...) ? Do you use the name of the server(or workstation) in the uri?

Coordinator
Jun 2, 2010 at 1:02 PM

Hello,

There is a problem with the version x64. I send frinseespstx64.zip  with the jar frinseespsttc6.jar,  the two dll. The name of the valve is fr.insee.spst.authneticator.SSPAuthenticator. The name of the Realm is fr.insee.spst.realm.WindowsRealm. I will compile again with fr.doume.....

Dominique  

Coordinator
Jun 3, 2010 at 6:41 AM

Hello,

There is a probleme with x64 and the native code in the dll. I will give a new version before Tuesday, June 15. I think, it is a problem between the garbage collector and the native code.

This problem does not exist with the version TCP. The java code sends the parameters to the Windows service via TCP. So you can use this version with the windows service without risks.  It works also with UNIX.

Dominique Guerin

 

Jun 3, 2010 at 8:03 AM

Thanks for the replies.

I got it running, and my problem was Tomcat not being started as a service. But I was starting it (using startup.bat) using a domain account with sufficient priviledges on the domain, what is the difference? Why doesn't that work?

And thanks for taking time to test the x64 version. I will probably switch to TCP version for platform independence, but I'm testing using DLL for now (on x86 windows).

What I'm doing now is to use parts of your code in a Servlet to identify the remote username, without loading the roles or filtering anything. I had to change some of the code, and remove the rest, but haven't got to the point that I can test it yet. Do you think this can work?

-Hamed

Coordinator
Jun 3, 2010 at 3:59 PM

Hello,

The browser tries Kerberos when the (DNS or Netbios) name of the server is is a Service Principal Name found in Active Directory, else it ties NTLM.

When tomcat is running with the account SYSTEM or Network Service, Tomcat is seen on the network via the account of the server, and there is a default Service Principal Name for this account (HOST\nameNetbios and HOST\DnsName).

By default, when tomcat is not running with the account SYSTEM or Network Service, the user cannot be authenticated with Kerberos. You can change this configutration . You must add a Service Pricipal Name HTTP\nameof theserver to another account with setspn.exe (cf configuration.txt)

To test with tomcat started with startup.bat, use the address of the server in the url.

To be simple, when you use SPNEGO, on Windows, use SYSTEM or Network Service and a service tomcat . Use only startup.bat to test the application.

If all users are on Active Directory, what is the problem? You can get the name of the user (cf the jsp code of the example)

Dominique

Jun 3, 2010 at 5:11 PM

Hi,

1. As you say, when I use startup.bat, there is no SPN mapping, so it will try NTLM. Why does NTLM fail in such a case? (This is just a curiosity, I was doing as you recommend, using startup.bat for testing, and tomcat service for production)

2. Not all users are on the active directory. This is a project that will be deployed in various environments, with different network setups. I want to give the option of using NTLM/Kerberos in case both client and server are members of the same domain. Otherwise, the application is already equipped with a fairly complex set of authorization features, and I will need to fallback to forms-based authentication. This is why I'm making a Servlet, to avoid setting the application pages as protected.

Thanks again for all your time and effort. Your project saves me a couple of days worth of hard and tiring work.

-Hamed

 

Jun 4, 2010 at 8:45 AM

Hi,

If it helps this is how I set up a fall-back.

I leave the bulk of the application unprotected and have a single folder which is protected (with a single JSP in it). If the application chooses to authenticate using IWA (turned on in admin settings) it forwards the user to the /auth/index.jsp. This uses the request.getRemoteUser() to set a session variable with the current username (using Wicket). The JSP then redirects back to the main application which completes the authentication either by matching the remote user to an account in the applications database or if there is no remote user (no Kerb/NTLM) or no match, by presenting a login screen.

 

Hope this is useful

Neil

Jun 4, 2010 at 9:27 AM

Hi,

Thanks Neil, this is exactly what I have planned to do, but I will try to do this using a Servlet.

That is because I can decide what to do with the Response in case I can't authorize the user. (I will redirect him to some other URL instead of returning 401).

I also like to contain the whole thing in the existing (single) webapp without making it dependent on the Tomcat itself, and without the need to setup Valves. If I do so, I need to place DLL and JAR files in Tomcat folders.

Jun 4, 2010 at 11:01 AM

Hi, I forgot to mention this above but I achieved this by mapping a 401 to a custom jsp in the web.xml as follows :

 <error-page>  <error-code>401</error-code>  <location>/failed.jsp</location> </error-page>

 

The jsp then forwards to the wicket page which bypasses IWA login and presents a login page.

Neil

Coordinator
Jun 7, 2010 at 6:57 PM

Hello,

1)To understand Kerberos and the Service principal Name:

http://alt.pluralsight.com/wiki/default.aspx/Keith.GuideBook.HomePage

item 59, 60 61.

2)If you want to use another servlet container, you cannot use a Valve. It is not in the servlet specification. You could use a Filter but a filter is not integrated with with the authorizations defined in the web.xml. Each servlet container gives a different solution...

3)To do that you want, I think it would be better to use Negoserver and not the dll.

Dominique

Jun 8, 2010 at 7:08 PM

Hello again.

1) Thanks, that is on my list of TO-DOs.

2) That's the point, I don't want the integration. I just want to get the username inside my application. That's why I'm using a servlet to do NTLM/Kerberos.

3) I'm actually using the NegoServer now. (I might create an MSI setup for it. If so, I will send it to you too. I can simplify the installation a little bit.) But I get a communication error (socket closed) in Java code, which I'm debugging. It should probably be my fault, since I changed the code a little to adapt it to Servlet spec. I will ask for your help if I couldn't figure out what is wrong.

4) Any news from the x64 fix?

Thanks again,

-Hamed

Coordinator
Jun 8, 2010 at 7:42 PM

Hello,

It is fixed.

I tarnslated the java code of the version TCP in english.

The class TranslationFromRolesIntoSids translates the names of the roles into SIDs when the first user comes. The class SSPAuthentication sends the SIDs to Negoserver. 

 Now , I must give the possibility to define the groups in another ldap directoty or in a SGBD. So  I must modify Negoserver, the class SSPAuthentication and the class SSPAuthentricator. After that, it will be easier to write a servlet.

Dominique 

 

Coordinator
Jun 10, 2010 at 6:50 AM

Hello,

You can download trunk-jna-1006210.zip. I replace the DLL by JNA (7mB). It works only on Windows.

In this version, I add a parameter nogroupsinad. So you can use another Realm to obtain the tomcat roles of the user. It is more easier to write a servlet. You have to copy and modify the code of SSPAuthenticator in your servlet.

I modify the code of the version Negoserver.  SSPAuthenticator is the same code in this version than with jna.

Dominique