I am a Senior IT Architecture Analyst, Developer and a Technical Evangelist. I started my career in 1996 as a freelancer. For last many years I work with Enterprise Java and various new technologies and platforms with different vendors. My main area of expertise is Core Java, Java EE, Spring technologies and RIA. Kapil Viren is a DZone MVB and is not an employee of DZone and has posted 10 posts at DZone. You can read more from them at their website. View Full User Profile

NTLM Authentication in Java

08.31.2011
| 10426 views |
  • submit to reddit

In one of my previous lives, I used to work in Microsoft and there this word – NTLM (NT Lan Manager) was something that came to us whenever we used to work on applications. Microsoft OS have always provided us with an inbuilt security systems that can be effectively used to offer authentication (and even authorization to web applications).

Many years back, I moved over into Java world and when I was asked to carry out my very first security implementation, I realized that there was no easy way to do this and many clients would actually want us to use LDAP for authentication and authorization. For many years, I continued to use that. And, then one day in a discussion with a client, we were asked to offer SSO implementation and client did not have an existing setup like SiteMinder. I started to think about if we can go about using NTLM based authentication. The reason that was possible was because the application we were asked to build was to be used within the organization itself and all the people were required to login into a domain.

After some research, I was able to find out a way we could do this. We did a POC and showed it to the client and they were happy about it. What we did has been explained below:

  • Wrote a Servlet which was the first one to be loaded (like Authentication Interceptor). This servlet was responsible for reading the header attributes and identify the user’s Domain and NTID
  • Once we had the details; we sent a request to our Database to see if that user is registered under the same domain/NTID
  • If the user was found in our user-database we allowed him to pass through
  • And then roles and authorization for user was loaded

Basically, we bypassed the “Login Screen” where the user was entering the password and used Domain information. Please note that it was possible for us because the Client guaranteed that there was this domain always and all users had unique NTIDs. Also, that it was their responsibility to shield the application from any external entry points where someone may impersonate the Domain/ID.

If you are interested, you can refer to the code below:

<%@ page import="sun.misc.BASE64Encoder" %>
<%
String auth = request.getHeader("Authorization");
String s = "";

//no auth, request NTLM
if (auth == null)
{
        response.setStatus(response.SC_UNAUTHORIZED);
        response.setHeader("WWW-Authenticate", "NTLM");
        return;
}

//check what client sent
if (auth.startsWith("NTLM "))
{
        byte[] msg =
           new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
        int off = 0, length, offset;

        if (msg[8] == 1) {
            off = 18;

            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};
            // send ntlm type2 msg

            response.setStatus(response.SC_UNAUTHORIZED);
            response.setHeader("WWW-Authenticate", "NTLM "
               + new sun.misc.BASE64Encoder().encodeBuffer(msg1).trim());

               return;
        }
        else if (msg[8] == 3) {
                off = 30;
                length = msg[off+17]*256 + msg[off+16];
                offset = msg[off+19]*256 + msg[off+8];
                s = new String(msg, offset, length);
                // print computer name // out.println(s + " ");
        }
        else
        return;

        length = msg[off+1]*256 + msg[off];
        offset = msg[off+3]*256 + msg[off+2];
        s = new String(msg, offset, length);
        //domain//out.println(s + " ");
        length = msg[off+9]*256 + msg[off+8];
        offset = msg[off+11]*256 + msg[off+10];

        s = new String(msg, offset, length);
        out.println("Hello  <span style="position: relative; width: 190px; height: 10px;">"); out.println(s + "</span>");
}
%>

 

From http://scrtchpad.wordpress.com/2011/08/04/ntml-authentication-in-java/

Published at DZone with permission of Kapil Viren Ahuja, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Gérald Quintana replied on Thu, 2011/09/01 - 3:25am

 Isn't there an error here (18 instead of 8)?

offset = msg[off+19]*256 + msg[off+18];

Why didn't you use JCIFS http://jcifs.samba.org/src/docs/ntlmhttpauth.html?

I heard NTLM was something from the past in MS world?

How secure is your solution: does the NTID change regularly? 

 I found your code here http://www.rgagnon.com/javadetails/java-0441.html are you really the author?

Kapil Viren Ahuja replied on Thu, 2011/09/01 - 8:05am in response to: Gérald Quintana

I checked once again and the code works fine for our needs. Changing the value will control what is extracted from the message. Based on what you need you can change the same.

 We used this code back in 2006-2007. Our requirements were very simple and this worked fine for us; hence we never researched or looked for any existing framework like JCIFS. I do not have comparison analysis between any of the framework and will not comment on any of those.

I did mention we used this few years ago, however when someone came about asking me a very simple solution to the problem, this one worked just fine. 

NTID do not change for a person, I have worked with 3 organizations and I never saw my Id change in any of those. About how secure this solution is, it has it shortcomings. I have spoken about a few assumptions we had to make while implementing this solution.

 The code reference you mentioned looks awfully similar, I am not aware of the code or how is these two codes so similar. When I posted this, I was browsing through my archived projects and found this in there; finding this useful I blogged about it. 4 years back when we did this, this was done by me (and my team).

Marcel AmmerlaanA replied on Thu, 2011/09/01 - 9:42am

The problem with this solution is that if you use firefox you can enter any username you like... so it's not very secure. For a 'controlled network' the solution might however be good enough.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.