How to determine if account running java application is 'SYSTEM'

609 views Asked by At

How can I check whether my Java application is running as "SYSTEM"/"Local System" (as seen on Windows Service list)?

Windows Service List

I tried using this:

System.out.println("Running with user: " + System.getenv().get("USERDOMAIN") + "\\" + System.getenv().get("USERNAME"));

... but it seems to return DOMAIN\COMPUTERNAME according where the program is run. So it can be like DOMAIN1\COMPUTER1 and somewhere else it is FOO\SERVER451 and both still means "SYSTEM" account.

For background information, my Java application is wrapped to a Windows Service with 'Apache Commons Daemon Service Runner' and by default it will run as "Local System" (same way as in example image).

I really would want to simplify my code to print either SYSTEM or MYDOMAIN\JackTheUser depending on user type... Is there a way to do it with Java?


EDIT 20/12/02: This is what I have done meanwhile the SO army working to find the correct answer:

    Main:
    String username = System.getenv().get("USERNAME");
    String userdomain = System.getenv().get("USERDOMAIN");
    String servername = getComputerName();

    if (username.equalsIgnoreCase((servername + "$"))) {
        System.out.println("Running with user: 'Local System'("
                + userdomain + "\\" + username + ")");
    } else {
        System.out.println("Running with user: '" + userdomain + "\\"
                + username + "'");
    }
    
    Methods:
    private static String getComputerName() {
        Map<String, String> env = System.getenv();
        if (env.containsKey("COMPUTERNAME"))
            return env.get("COMPUTERNAME");
        else if (env.containsKey("HOSTNAME"))
            return env.get("HOSTNAME");
        else
            return "Unknown Host name";
    }

Prints:

Running with user: 'MYDOMAIN\jokkeri' or Running with user: 'Local System'(MYSERVER\SERVER_1$)

(not a perfect solution and I'm sure there are many occasions where it won't work but it's a starting point)


EDIT2 20/12/02: Some good information about SYSTEM account was found from this thread from superuser: https://superuser.com/questions/265216/windows-account-ending-with

1

There are 1 answers

0
Holger On BEST ANSWER

That’s the best I can come up so far

private static final String APP_NAME = "Some App";

private static final Configuration CONFIG = new Configuration() {
  public @Override AppConfigurationEntry[] getAppConfigurationEntry(String name) {
      return name.equals(APP_NAME)?
          new AppConfigurationEntry[] { new AppConfigurationEntry(
              "com.sun.security.auth.module.NTLoginModule",
              LoginModuleControlFlag.REQUIRED, Collections.emptyMap())}:
          null;
  }
};

static final boolean DEBUG = true;

public static void main(String[] args) throws LoginException {
    LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
    lc.login();
    final Subject subject=lc.getSubject();
    boolean isSystem = false;
    try {
        for(Principal p: subject.getPrincipals()) {
            if(DEBUG) System.out.println(p);
            if(p.toString().equals("NTSidUserPrincipal: S-1-5-18")) {
                isSystem = true;
                if(DEBUG) System.out.println("\tit's SYSTEM");
            }
        }
    }
    finally { lc.logout(); }
}

As explained in this answer, SYSTEM is a set of permissions that can be attached to different accounts. The code iterates over all principals associated with the current account and tests for the well known SYSTEM.

But if you’re only interested in a printable user name, you may check for the NTUserPrincipal.

LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
lc.login();
final Subject subject=lc.getSubject();
try {
    String name = System.getProperty("user.name"); // just a fall-back
    for(Principal p: subject.getPrincipals()) {
        if(p.toString().startsWith("NTUserPrincipal: ")) {
            name = p.getName();
            break;
        }
    }
    System.out.println("Hello " + name);
}
finally { lc.logout(); }

If you can live with a direct dependency to the com.sun.security.auth package (or jdk.security.auth module in Java 9+), you can use the specific principal types directly

LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
lc.login();
final Subject subject=lc.getSubject();
try {
    boolean system = false;
    for(NTSidUserPrincipal p: subject.getPrincipals(NTSidUserPrincipal.class)) {
        if(p.getName().equals("S-1-5-18")) {
            system = true;
            break;
        }
    }
    Set<NTUserPrincipal> up = subject.getPrincipals(NTUserPrincipal.class);
    String name = up.isEmpty()?
        System.getProperty("user.name"): up.iterator().next().getName();

    System.out.println("Hello " + name+(system? " *": ""));
}
finally { lc.logout(); }