Java thick client authentication with Kerberos

May 1, 2011 at 7:58 PM

For a while now I've been trying to identify the currently logged on userid from a java thick client, without additional prompts, and in a manner that the user cannot spoof. 

The good news first:  One can accomplish this without  the fussy GSSContext.InitSecContext strategy which I and many others could never get working. 

Here's how:  Create a IWA protected web page on a kerberized IIS server in your intranet.  Have that page return the user's logon name (and other data you might want) from the server side.  (For instance, the server side include REMOTE_USER.  This will be blank unless the user has authenticated. )  Last, fetch that page from your thick client using java.net.Authenticator (example below).

This is great, but I'd rather not use IIS, but Tomcat or WebLogic.  Can I use my code below to point to a "Waffle protected" page on Tomcat instead, e.g. http://localhost:8080//waffle-negotiate  ?  Will Waffle negotiate with Active Directory and figure out the user name?

The disturbing thing is that I tried this, and it appeared to work.  But then I happened to reboot, start up Tomcat, and, without VPNing into my company firewall, ran again.  It gave me the user name!  But obviously it was just my name logging onto my machine, not the company intranet.  So, the question is, how can I ensure that waffle-negotiate actually communicated with the AD server to get the name?

Here is my code, the HTML response, and finally the tomcat log.  I am not logged into my company intranet at this point.


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;

public class RunHttpSpnego
{

  static final String kuser = "username"; // your account name
  static final String kpass = "password"; // your password for the account

  static class MyAuthenticator extends Authenticator
  {
    public PasswordAuthentication getPasswordAuthentication()
    {
      // I haven't checked getRequestingScheme() here, since for NTLM
      // and Negotiate, the usrname and password are all the same.
      System.err.println("Feeding username and password for "
          + getRequestingScheme());
      return (new PasswordAuthentication(kuser, kpass.toCharArray()));
    }
  }

  public static void main(String[] args) throws Exception
  {
    Authenticator.setDefault(new MyAuthenticator());
    URL url = new URL("http://localhost:8080/waffle-negotiate/");
    InputStream ins = url.openConnection().getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(ins));
    String str;
    while ((str = reader.readLine()) != null)
      System.out.println(str);
    System.out.println(url.getUserInfo());
  }
}


<html>
 <head>
  <title>Protected Page for Examples</title>
 </head>
 <body bgcolor="white">
  You are logged in as remote user <b>AD\a031563</b> in session <b>96444CC5C8655ECD104795AEEA86A15C</b>.
  <br><br>
 
  Your user principal name is <b>AD\a031563</b>.
  <br><br>
 
 
  To check whether your username has been granted a particular role, enter it here:
  <form method="GET" action='index.jsp;jsessionid=96444CC5C8655ECD104795AEEA86A15C'>
   <input type="text" name="role" value="">
  </form>
  <br><br>
  You can logoff by clicking
  <a href='index.jsp;jsessionid=96444CC5C8655ECD104795AEEA86A15C?logoff=true'>here</a>.
  This should cause automatic re-logon with Waffle and a new session ID.
 </body>
</html>
null

Tomcat Log Files:

INFO: successfully logged in user: AD\a031563
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: GET /waffle-negotiate/, contentlength: -1
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: authorization: <none>, ntlm post: false
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: authorization required
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: GET /waffle-negotiate/, contentlength: -1
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: authorization: NTLM TlRMTVNTUAABAAAAB7IIogIAAgA3AAAADwAPACgAAAAFASgKAAAAD0RFTkwtQ05VMDQwMjhSM0FE, ntlm post: false
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: security package: NTLM, connection id: 127.0.0.1:1788
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: token buffer: 57 byte(s)
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: continue required: true
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: continue token: TlRMTVNTUAACAAAABAAEADgAAAAFwomiPGQrrj3vPAsoQEABAAAAALoAugA8AAAABQEoCgAAAA9BAEQAAgAEAEEARAABAB4ARABFAE4ATAAtAEMATgBVADAANAAwADIAOABSADMABAAgAGEAZAAuAHUAbABhAGwAYQB1AG4AYwBoAC4AYwBvAG0AAwBAAEQARQBOAEwALQBDAE4AVQAwADQAMAAyADgAUgAzAC4AYQBkAC4AdQBsAGEAbABhAHUAbgBjAGgALgBjAG8AbQAFACAAYQBkAC4AdQBsAGEAbABhAHUAbgBjAGgALgBjAG8AbQAAAAAA
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: GET /waffle-negotiate/, contentlength: -1
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: authorization: NTLM TlRMTVNTUAADAAAAAAAAAEgAAAAAAAAASAAAAAAAAABIAAAAAAAAAEgAAAAAAAAASAAAAAAAAABIAAAABcKIogUBKAoAAAAP, ntlm post: false
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: security package: NTLM, connection id: 127.0.0.1:1788
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: token buffer: 72 byte(s)
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: continue required: false
May 1, 2011 1:48:02 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: logged in user: AD\a031563 (S-1-5-21-3330063658-4172511837-1669859525-11684)
May 1, 2011 1:48:04 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: roles: AD\a031563, BUILTIN\Administrators, BUILTIN\Users, Everyone, LOCAL, NT AUTHORITY\Authenticated Users, NT AUTHORITY\INTERACTIVE, S-1-1-0, S-1-2-0, S-1-5-11,

[Here are many lines of S-1-5-21.... that I deleted]

 

May 1, 2011 1:48:04 PM waffle.apache.NegotiateAuthenticator authenticate
FINE: session id:5332C3D06390C9B0EA09412AF8891927
May 1, 2011 1:48:04 PM waffle.apache.NegotiateAuthenticator authenticate
INFO: successfully logged in user: AD\a031563

May 2, 2011 at 4:08 AM

I should add that this problem does not depend on my Java code.  Even if I just log onto my machine, start Tomcat, and bring up my protected page in IE, is shows my account name.  Since I have not logged into
my company windows domain yet, it should prompt me for a password.  In Firefox, it does prompt me.

Coordinator
May 2, 2011 at 2:27 PM

What Waffle does and what IIS does is the exact same thing. You being logged in to your computer and connecting to your local machine yields your user name. What's wrong with that?

The whole remote part of it is just a transport - Negotiate protocol allows a client to connect to a server "as the currently logged on user" (local or domain). If your server were in the domain and your client were not, then you would get a 401.

What you're doing is still solving a problem you don't have IMHO. Asking a server to give you the username has the same effect as doing GetUserName on the client. The client can pretend to be anything after it has asked the server.