Posts Tagged ‘NTLM Authentication’

NTLM Authentication

Tuesday, March 24th, 2009

Introduction:

This BOK details how to get a Java-based web-application to negotiate with a IE web client for username and domain information. This is a common requirement for web-based applications especially ones that do not want to bore users with a login page. IE will negotiate a user’s password hashes with the webserver, which checks their authenticity against a windows domain controller. If valid, the user’s username and domain will be accessible to the webserver servlets.

NTLM Authentication and how we achieve it:

 
The method HttpServletRequest.getRemoteUser() should return the username of the person using the browser which fired a request to this Servlet.
This method, however works correctly only if the user has been authenticated first by a webserver authentication scheme -
which could be BASIC,DIGEST or CLIENT-CERT. This is the kind of setup the the Apache webserver provides, giving a challenge-response, username-password method of authentication.

What we do here is use a Servlet filter provided as part of the open-source jCIFS package, to get an IE user's username and domain. 

This filter will take the trouble of intercepting user requests, asking IE for the user's password hashes,validating them against a windows domain controller and enabling HttpServletRequest.getRemoteUser() to return the windows user id.
 
Please note this method will not work for non-IE clients, simply because this is a proprietary extension by Microsoft. 
 
For other browsers you will have to rely on BASIC or certificate-based authentication.

How to setup your web application:

 First, we need to download a jcifs jar from http://jcifs.samba.org. I have tested this with jcifs version 0.7.14.jCIFS is from the makers of Samba and provides APIs to access Windows shares, networks and the ability to authenticate against a Windows domain controller. Place this jar under WEB-INF/lib of your web application. There is a filter called jcifs.http.NtlmHttpFilter which implements all the wizadry above. You need to register it in your application's web.xml descriptor:
 
<web-app>
...
    <!-- NTLM HTTP Authentication only works with MSIE -->
    
    <filter>
        <filter-name>NTLM HTTP Authentication Filter</filter-name>
        <filter-class>jcifs.http.NtlmHttpFilter</filter-class>

        <!-- CCD will help you with a PDC and WINS server ip at your location. -->
        <init-param>
            <param-name>jcifs.http.domainController</param-name>
            <param-value>192.168.170.5</param-value>
        </init-param>

        <init-param>
            <param-name>jcifs.netbios.wins</param-name>
            <param-value>192.168.166.13</param-value>
        </init-param>
    </filter>

    <!-- This is the url under which we need access to the username and domain. -->

    <filter-mapping>
        <filter-name>NTLM HTTP Authentication Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

...

</web-app>
 
That's it. Now all IE requests to your webserver urls as specified in the web.xml entries are negotiated so that you can call a HttpServletRequest.getRemoteUser() to get the remote user's username in the form.

            DOMAIN\username.

Please note at no point will a password dialog pop up for the user, the password hashes are picked from IE and validated with the domain controller.
 
 
Example code for a servlet :
 
 
public void doGet( HttpServletRequest req,
                        HttpServletResponse resp )
throws IOException, ServletException
        
        {

PrintWriter out = resp.getWriter();

resp.setContentType( “text/html” );
out.println( “<HTML><HEAD><TITLE>NTLM HTTP Authentication Example</TITLE></HEAD><BODY>” );
out.println( “<h2>NTLM HTTP Authentication Example</h2>” );

out.println( req.getRemoteUser() + ” logged in” );

 

}

If the filter has not been configured properly, a null will be printed for the above call to req.getRemoteUser().

 

References:

  • Web Link :- http://jcifs.samba.org.