Obtaining non-spoofable user name

Apr 14, 2011 at 10:58 PM

Hello, I have a windows client for which I want to find the currently logged on user's AD account name.

I'd like to do it in a reliable manner that cannot be spoofed, that is, AD\bob cannot tweak his memory to make this software think he is AD\frank. 

Will this code do it?  If it is vulnerable, is there something i can add to make it less vulnerable?

import waffle.windows.auth.IWindowsAccount;
import waffle.windows.auth.impl.WindowsIdentityImpl;
import com.sun.jna.LastErrorException;
import com.sun.jna.platform.win32.Advapi32;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;

public class GetUser

{
  public static void main(String[] args)
  {
    HANDLEByReference phToken = null;
    try
    {
      phToken = new HANDLEByReference();
      HANDLE threadHandle = Kernel32.INSTANCE.GetCurrentThread();
      if (!Advapi32.INSTANCE.OpenThreadToken(threadHandle,

          WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY, true, phToken))
      {
        HANDLE processHandle = Kernel32.INSTANCE.GetCurrentProcess();

        if (!Advapi32.INSTANCE.OpenProcessToken(processHandle,
            WinNT.TOKEN_DUPLICATE | WinNT.TOKEN_QUERY, phToken))
        {
          throw new LastErrorException(Kernel32.INSTANCE.GetLastError());
        }
      }
      try
      {
        WindowsIdentityImpl id = new WindowsIdentityImpl(phToken.getValue());
        String idFQDN = id.getFqn();
        System.out.println("User is: " + idFQDN);

      }
      catch (Exception e)
      {
        System.err.println("Failed to access currently logged on user: "
            + e.getMessage());
      }
    }
    catch (Exception e)
    {
      System.err.println("Failed to get token for currently logged on user: "
          + e.getMessage());
    }
    finally
    {
      if (phToken != null)
        Kernel32.INSTANCE.CloseHandle(phToken.getValue());
    }
  }
}

Coordinator
Apr 15, 2011 at 12:28 AM

It's as secure as a call to any Win32 API, including GetCurrentUser() (simpler way of getting a username). That is, that executes something in kernel mode, then returns a username into the user space with the username in there. That block is read by the application that runs as the user - who can open the current process token and maybe stand on his head by modifying the current application's data.

So, I think the right question is: what scenario are you trying to protect?

Apr 15, 2011 at 2:01 AM

I have a Java thick client in which I would like to get the the AD username, then access data by communicating with WebLogic, based on who the user is, all with no new prompts for password.  From other posts here, I realize there is a reasonable objection that one might disassemble my thick client and provide any AD name one might choose.  I am thinking that bytecode obfuscation of that part of the code might prevent that line attack.  http://www.yworks.com/en/products_yguard_about.htm.

What are people's opinion of this?  My app is inside a company firewall.  If that seems like not enough protection, I will probably try Waffle with Weblogic.

Coordinator
Apr 15, 2011 at 3:09 PM

Before I answer, lets imagine that the user doesn't use your app and uses his HackerApp. What prevents HackerApp from talking to your WebLogic server and pretending like the user is someone else?

Apr 18, 2011 at 8:18 PM

Not sure I can answer that question adequately.  Signed Jar files are deployed from a WebLogic Server to user's desktop using Java Web Start.  Those downloaded classes use RMI to execute classes within the WebLogic server.  I would have thought that the Weblogic server would reject any calls from a client that were not from a jar file with a signature that WebLogic recognizes.  If that is true, then what remains is to make sure that the client side classes obtain the user's identity in a way that cannot be spoofed.  So, can GetCurrentUser() be spoofed?

Coordinator
Apr 18, 2011 at 8:29 PM

If the user is Administrator on the client he can do anything. If he's not, I think the amount of hooking possible is limited, but there're plenty of exploits of token hijacking, so I wouldn't count on that. Client-side-only authentication with a signed JAR isn't going to pass a security review IMHO, even if nobody can come up with a working hack. I would implement a web service on Weblogic, forget the whole signed business and do windows authentication with the server.

Apr 19, 2011 at 9:00 PM

I was pleased to be able to get the waffle-negotiate sample working!  However, I'm still unclear on which flavor Waffle to use.  Again, I have a java thick client, and I want to authenticate without any additional user/password prompts. (The users feel they've authenticated enough, having logged into windows in the morning.)  Waffle-negotiate works great from a browser, but I'm not using a browser.  Waffle-jaas looks more like it, but unless I misunderstand, it is going to prompt for user/password.  Could you recommend which way to go?

Coordinator
Apr 19, 2011 at 10:02 PM

Now that you have the server working, implement the client-side with waffle (or something else that supports the Negotiate protocol) as well. It really depends what the client app is - I think some people have posted info on making swing apps do Negotiate somewhere in this forum.

Apr 20, 2011 at 4:23 PM

I don't think there is any Swing or thick client app in these discussions that has done this.  Mermeister talked about it, but no code example.

Discussion boards are littered with threads of people trying to do this.  People reference this or that "working code",  but the working code doesn't work for many people, judging by comments.  The treads wind down with people giving up, usually stuck on  GSSContext.initSecContext.

So, I thought, what if my thick client could create an "invisible browser" session, that would  call waffle-negotiate ?  Maybe that is naive.  Anyway, here is my code and its results.

    HttpClient client = new HttpClient();
    HttpMethod method = new GetMethod("http://localhost:8080/waffle-negotiate/");

    try
    {
      client.executeMethod(method);

      if (method.getStatusCode() == HttpStatus.SC_OK)
      {
        String response = method.getResponseBodyAsString();
        System.out.println("Response = " + response);

Results are:

INFO: ntlm authentication scheme selected
Apr 20, 2011 10:17:58 AM org.apache.commons.httpclient.HttpMethodDirector processWWWAuthChallenge
INFO: No credentials available for NTLM <any realm>@localhost:8080

 

Coordinator
Apr 20, 2011 at 4:59 PM

Those are all client-side problems, I really don't know anything about this. But what protocol/api does your swing app to to with the server?