0

如何检查我的 Java 应用程序是否作为“系统”/“本地系统”运行(如 Windows 服务列表中所示)?

Windows 服务列表

我尝试使用这个:

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

...但它似乎DOMAIN\COMPUTERNAME根据程序运行的位置返回。所以它可以像DOMAIN1\COMPUTER1其他地方一样,FOO\SERVER451并且都仍然意味着“系统”帐户。

对于背景信息,我的 Java 应用程序使用“Apache Commons Daemon Service Runner”包装到 Windows 服务中,默认情况下它将作为“本地系统”运行(与示例图像中的方式相同)。

我真的很想简化我的代码以打印SYSTEMMYDOMAIN\JackTheUser根据用户类型...有没有办法用Java来做?


编辑 20/12/02:这就是我在 SO 军队努力寻找正确答案的同时所做的事情:

    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";
    }

印刷:

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

(不是一个完美的解决方案,我敢肯定在很多情况下它不起作用,但这是一个起点)


EDIT2 20/12/02:从超级用户的这个线程中找到了一些关于 SYSTEM 帐户的好信息:https ://superuser.com/questions/265216/windows-account-ending-with

4

1 回答 1

2

这是迄今为止我能想到的最好的

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(); }
}

正如这个答案中所解释的,SYSTEM 是一组可以附加到不同帐户的权限。该代码遍历与当前帐户关联的所有主体并测试众所周知的 SYSTEM。

但是,如果您只对可打印的用户名感兴趣,则可以检查 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(); }

如果您可以直接依赖于com.sun.security.auth包(或jdk.security.authJava 9+ 中的模块),则可以直接使用特定的主体类型

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(); }
于 2020-12-02T16:49:56.620 回答