Detect if Java application was run as a Windows admin
Asked Answered
L

8

22

I have a Java application. Is there anyway I can tell if the process was run with admin privileges, on Windows 7.

Labourer answered 3/12, 2010 at 22:19 Comment(1)
I tested my answer in Linux. It's probably not OS-dependent, but I can't tell.Poisoning
D
19

I found this code snippet online, that I think will do the job for you.

public static boolean isAdmin() {
    String groups[] = (new com.sun.security.auth.module.NTSystem()).getGroupIDs();
    for (String group : groups) {
        if (group.equals("S-1-5-32-544"))
            return true;
    }
    return false;
}

It ONLY works on windows, and comes built in to the core Java package. I just tested this code and it does work. It surprised me, but it does.

The SID S-1-5-32-544 is the id of the Administrator group in the Windows operating system.

Here is the link for more details of how it works.

Dillingham answered 3/12, 2010 at 23:1 Comment(5)
Good ol' S-1-5-32-544. I should have thought of that.Relax
... And only with a Sun JVM due to private classes.Greyhen
Note this snippet tests whether the active user is an Administrator, instead of whether the user has launched the application as an elevated process!Eroticism
This doesn't work if the application is ran with normal rights on the administrator account. Still returns true...Latrishalatry
This code will likely only work with Oracle JRE and is not guaranteed to work with any update to the JRE: oracle.com/technetwork/java/faq-sun-packages-142232.htmlQualls
B
38

I've found a different solution that seems to be platform-independent. It tries to write system-preferences. If that fails, the user might not be an admin.

As Tomáš Zato suggested, you might want to suppress error messages caused by this method. You can do this by setting System.err:

import java.io.OutputStream;
import java.io.PrintStream;
import java.util.prefs.Preferences;

import static java.lang.System.setErr;
import static java.util.prefs.Preferences.systemRoot;

public class AdministratorChecker
{
    public static final boolean IS_RUNNING_AS_ADMINISTRATOR;

    static
    {
        IS_RUNNING_AS_ADMINISTRATOR = isRunningAsAdministrator();
    }

    private static boolean isRunningAsAdministrator()
    {
        Preferences preferences = systemRoot();

        synchronized (System.err)
        {
            setErr(new PrintStream(new OutputStream()
            {
                @Override
                public void write(int b)
                {
                }
            }));

            try
            {
                preferences.put("foo", "bar"); // SecurityException on Windows
                preferences.remove("foo");
                preferences.flush(); // BackingStoreException on Linux
                return true;
            } catch (Exception exception)
            {
                return false;
            } finally
            {
                setErr(System.err);
            }
        }
    }
}
Beker answered 8/5, 2014 at 10:18 Comment(11)
Good, but I suggest that you cache the status into private static variable. It's not gonna change within one instance of the program.Booker
@TomášZato You're definetly right that it won't change, but I wanted to make the code-example as short as possibleBeker
One more thing - the function keeps producing output, such as Kvě 07, 2015 1:49:14 ODP. java.util.prefs.WindowsPreferences <init> WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5. Is it possible to surpress these?Booker
@TomášZato I improved my answerBeker
Thanks a lot! :) Unfortunatelly, I can't upvote you a second time. Hopefully, someone else will.Booker
This is the true solution that works. Suppression is important. +1Latrishalatry
Note that the second code block in the answer throws a NullPointerException, due to System.setErr(null). To fix that, use a dummy output stream instead: System.setErr(new PrintStream(new OutputStream() { @Override public void write(int i) throws IOException { } }));Transvalue
The line synchronized(systemErr) has no effect if the other Threads doesn't synchronize to System.err too.Slesvig
+1 because this detects (what I think is called) administrative context, not just administrative users. I am an administrator on my PC but most of the time I am not running programs with administrative rights. For the above to return true, I must execute my program using Run as Administrator, which is different than just running a program as a user who is part of the administrators group.Trifoliate
Setting that empty error stream did not work for me, I still got the error output. Since Java 11, OutputStream has a built-in static method to create a "null output stream", though, accessed via nullOutputStream(). That one works. Maybe it's because a different overload for write() is called on it, while this answer only overrides one of them. The built-in null stream one overrides all of them.Discourse
Also, setting the error stream back to System.err also didn't work for me. I think setErr() already sets a new "standard" output stream? So System.err after that just refers to our "null stream" again. Saving the current System.err stream in a variable before calling setErr(), and then setting it back to that in the finally {} block, worked for me.Discourse
D
19

I found this code snippet online, that I think will do the job for you.

public static boolean isAdmin() {
    String groups[] = (new com.sun.security.auth.module.NTSystem()).getGroupIDs();
    for (String group : groups) {
        if (group.equals("S-1-5-32-544"))
            return true;
    }
    return false;
}

It ONLY works on windows, and comes built in to the core Java package. I just tested this code and it does work. It surprised me, but it does.

The SID S-1-5-32-544 is the id of the Administrator group in the Windows operating system.

Here is the link for more details of how it works.

Dillingham answered 3/12, 2010 at 23:1 Comment(5)
Good ol' S-1-5-32-544. I should have thought of that.Relax
... And only with a Sun JVM due to private classes.Greyhen
Note this snippet tests whether the active user is an Administrator, instead of whether the user has launched the application as an elevated process!Eroticism
This doesn't work if the application is ran with normal rights on the administrator account. Still returns true...Latrishalatry
This code will likely only work with Oracle JRE and is not guaranteed to work with any update to the JRE: oracle.com/technetwork/java/faq-sun-packages-142232.htmlQualls
R
6

There is not such a facility available in the Java Runtime Environment, but might be in a platform-dependent native routine. Note that usually the best way to be certain is to actually try to do it, and see if it fails.

Rozalie answered 3/12, 2010 at 22:21 Comment(0)
A
3

Only by attempting an operation which requires such access (like binding a low-numbered port, or opening a known-to-be-protected file).

Appendage answered 3/12, 2010 at 22:22 Comment(1)
Thanks. That worked for me. I attempted to create a test file in program files and caught IOException (Access is Denied)... new File(System.getenv("programfiles")+"/test.tst").createNewFile()Clanton
H
2

The method from the answer marked best worked nicely for me until the point when I had to build the code in Jenkins on a Linux machine. com.sun.security.auth.module.NTSystem() is not available there and using sun packages is generally considered a bad practice: link

Hecht answered 7/3, 2012 at 10:57 Comment(2)
Grab the “rt.jar” from your windows machine. Add it to the class path on your Linux machine. Then have code inside your app that can see if its a windows PC, execute the accepted answer, if its Linux, run the Linux answers from this question. First solution that comes to mind. For me, I just needed to do this on Windows, so I didnt have this problem. Its one of those things where Java kind of sucks at doing. Just a side note, you should add this as a comment.Labourer
Thanks for the hint regarding the rt.jar! I will give it a try. PS:I know, that this should have been a comment, but unfortunately, due to the somewhat weird way stackoverflow gives permissions, with my current reputation I am only allowed to comment on my own answers/questions =)Hecht
V
0

Here is a solution on Windows 10, I guess that it runs properly on other Windows OS too.

public static boolean isAdmin() {
    try {
        ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe");
        Process process = processBuilder.start();
        PrintStream printStream = new PrintStream(process.getOutputStream(), true);
        Scanner scanner = new Scanner(process.getInputStream());
        printStream.println("@echo off");
        printStream.println(">nul 2>&1 \"%SYSTEMROOT%\\system32\\cacls.exe\" \"%SYSTEMROOT%\\system32\\config\\system\"");
        printStream.println("echo %errorlevel%");

        boolean printedErrorlevel = false;
        while (true) {
            String nextLine = scanner.nextLine();
            if (printedErrorlevel) {
                int errorlevel = Integer.parseInt(nextLine);
                return errorlevel == 0;
            } else if (nextLine.equals("echo %errorlevel%")) {
                printedErrorlevel = true;
            }
        }
    } catch (IOException e) {
        return false;
    }
}
Viosterol answered 24/8, 2018 at 7:9 Comment(0)
H
0

Below code worked out for me

Command prompt command

net user

Java code

public static  boolean isAdmin() {
        StringBuilder outputbuilder = new StringBuilder();
    try {
        ProcessBuilder builder = new ProcessBuilder(
                "cmd.exe","/c" ,"net user");
        builder.redirectErrorStream(true);
        Process p = builder.start();
        BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        while (true) {
            line = r.readLine();
            if (line == null) { break; }
            outputbuilder.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
    System.out.println(outputbuilder.toString());
    return outputbuilder.toString().contains("Administrator");
}
Hypothalamus answered 14/2, 2019 at 18:46 Comment(0)
P
-1

Or you could do this:

System.getenv().get("USER")

And see which user started the process.

When I run it as me I get "goran", when I run it with sudo I get "root". Works on Linux. Probably what was needed.

Poisoning answered 3/12, 2010 at 22:25 Comment(8)
Hmm, this is interesting, let me try this and see what it does on windows. If it says "admin" this will work.Labourer
And please, post your results. I'd really like to know if this is OS-independentPoisoning
On Windows 7, I get a null if I run this code. However, if I run System.getProperty("user.name"), I get my username. But, this still does not tell if I am admin or not.Dillingham
Interesting. Try getting all the properties: System.out.println(System.getenv()); Maybe, there is something else.Poisoning
Also try: System.out.println(System.getProperties());Poisoning
Ok, based on what you and Codemwnci said, this obviously works quite differently on Windows, so you'll have to do the try-and-see thing others suggested.Poisoning
Using getenv(), the key is USERNAME, so your code would be System.getenv().get("USERNAME"), the result is the same as System.getProperty("user.name")Dillingham
Well, my getenv contains both keys. Until now i didn't even notice "USERNAME"Poisoning

© 2022 - 2024 — McMap. All rights reserved.