106

How can I get the username/login name in Java?

This is the code I have tried...

try{
    LoginContext lc = new LoginContext(appName,new TextCallbackHandler());
    lc.login();
    Subject subject = lc.getSubject();
    Principal principals[] = (Principal[])subject.getPrincipals().toArray(new Principal[0]);

    for (int i=0; i<principals.length; i++) {
        if (principals[i] instanceof NTUserPrincipal || principals[i] instanceof UnixPrincipal) {
            String loggedInUserName = principals[i].getName();
        }
    }

}
catch(SecurityException se){
    System.out.println("SecurityException: " + se.getMessage());
}

I get a SecurityException when I try to run this code. Could someone please tell me whether I'm heading in the right direction, and help me to understand the problem.

Machavity
  • 30,841
  • 27
  • 92
  • 100
George Profenza
  • 50,687
  • 19
  • 144
  • 218
  • 4
    I'm afraid to misunderstand you, but I don't understand your question. Which login username? Windows/GNU Linux login? Basic authentication on a webserver? – guerda Apr 28 '09 at 12:26
  • It's impossible to understand anything when no details are posted – matt b Apr 28 '09 at 12:35

9 Answers9

258
System.getProperty("user.name");
George Profenza
  • 50,687
  • 19
  • 144
  • 218
dfa
  • 114,442
  • 31
  • 189
  • 228
  • 4
    +1 you can print the System.properties to get a lot of informations the VM is initialized with – Markus Lausberg Apr 28 '09 at 12:15
  • 4
    For me this prints the name of the user executing the VM. Not the logged in user on the java application. – The Student Jun 02 '16 at 14:36
  • 1
    Is this defined anywhere in a widely available third party library? Or is there a constant defined anywhere in JDK provided classes for the `user.name` property name? – Jeff Evans Jun 03 '20 at 04:26
  • There's no constant field defining the property name, but it is defined in the apidoc of [`System.getProperties()`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/System.html#getProperties%28%29): _"This set of system properties always includes values for the following keys"_. – Stanimir Stamenkov Jul 10 '23 at 14:38
29

in Unix:

new com.sun.security.auth.module.UnixSystem().getUsername()

in Windows:

new com.sun.security.auth.module.NTSystem().getName()

in Solaris:

new com.sun.security.auth.module.SolarisSystem().getUsername()
newacct
  • 119,665
  • 29
  • 163
  • 224
  • 53
    This code goes against Java's philosophy of write once, run anywhere (introduction of OS specific code), and secondly, it creates a dependency on Sun's implementation of Java. – Jin Kim May 19 '09 at 16:28
  • 14
    Trying to get the username is by definition platform-specific. A JVM running on a single-user system might not have a username at all. – Chinmay Kanchi Feb 18 '10 at 16:58
  • 9
    @ChinmayKanchi: If there's no username, then the `user.name` property should just be null. I agree with @JinKim, don't write OS-dependent stuff. – Mr. Lance E Sloan Oct 26 '11 at 15:25
  • 2
    user.name can be set on the command-line, so it very much depends what the use-case is – Alice Purcell Mar 21 '14 at 16:27
  • 5
    Classes under com.sun packages, should not be used by a developer. They are internal and may change in the future. – CHiRo79 Aug 11 '14 at 14:15
  • The `com.sun` classes are not accessible by default in Java 9+. This solution will not work for it. – Thunderforge Sep 25 '18 at 18:55
  • @Thunderforge com.sun.security.auth.module.NTSystem still exists in Java17 , UnixSystem and SolarisSystem does not. – trilogy Jun 15 '22 at 16:02
17

inspired by @newacct's answer, a code that can be compiled in any platform:

String osName = System.getProperty( "os.name" ).toLowerCase();
String className = null;
String methodName = "getUsername";

if( osName.contains( "windows" ) ){
    className = "com.sun.security.auth.module.NTSystem";
    methodName = "getName";
}
else if( osName.contains( "linux" ) ){
    className = "com.sun.security.auth.module.UnixSystem";
}
else if( osName.contains( "solaris" ) || osName.contains( "sunos" ) ){
    className = "com.sun.security.auth.module.SolarisSystem";
}

if( className != null ){
    Class<?> c = Class.forName( className );
    Method method = c.getDeclaredMethod( methodName );
    Object o = c.newInstance();
    System.out.println( method.invoke( o ) );
}
onlyhuman
  • 381
  • 3
  • 10
celsowm
  • 846
  • 9
  • 34
  • 59
  • Good use of reflection :) – Zizouz212 Jan 08 '16 at 01:22
  • 5
    This will break on Windows since the method on NTSystem to get the username is "getName()" and not "getUsername()". I suppose you can do a further check and then invoke the right method. Bizarre this isn't abstracted into an OS agnostic mechanism by the JRE though? – John Mark Scarborough Aug 19 '16 at 07:02
  • 1
    The `com.sun` classes are not accessible by default in Java 9+. This solution will not work for it. – Thunderforge Sep 25 '18 at 18:55
  • Unless some new API was added, I think the only thing that will work in Java 9 would be [dfa's solution](https://stackoverflow.com/a/797569/531762). – Thunderforge Sep 26 '18 at 21:25
  • 1
    @Thunderforge Tested it on Java 17, looks like com.sun.security is still there. – trilogy Jun 15 '22 at 15:37
16

System.getProperty("user.name") is not a good security option since that environment variable could be faked: C:\ set USERNAME="Joe Doe" java ... // will give you System.getProperty("user.name") You ought to do:

com.sun.security.auth.module.NTSystem NTSystem = new com.sun.security.auth.module.NTSystem();
System.out.println(NTSystem.getName());

JDK 1.5 and greater.

I use it within an applet, and it has to be signed. info source

pdjota
  • 3,163
  • 2
  • 23
  • 33
  • 4
    This isn't a complete solution, since it only works under Windows. – Mr. Lance E Sloan Oct 26 '11 at 16:39
  • 1
    Could this be spoofed too, e.g. with a custom classloader or a custom implementation of `com.sun.security.auth.module.NYSystem` higher in the classpath? I don't know if the Java runtime tries to prevent against such exploits, but I don't think there will be any unfakeable way to make it 'secure' except by running code on a box that is inaccessible to the potentially-malicious client. – bacar Aug 13 '12 at 17:31
  • 4
    I just successfully managed to replace the implementation of NTSystem.getName() using PowerMock (which I believe uses a custom classloader), so you really can't rely on something like this for 'security'... however I don't know how things are in the applet world. I would have thought that if someone can provide custom system properties then they can also provide custom classes or custom classloaders. – bacar Aug 13 '12 at 17:59
  • 1
    -1 Because it only works on Windows. You should NOT use this. – jobukkit Sep 16 '13 at 12:52
  • @bacar: I agree, that one shouldn't rely on this and think one is pretty secure. But in my opinion security is about "levels". And it's way easier to change the environment variable than powermocking a method. In a non-IT company using NTSystem rather than the environment variable more than halves the amount of people who are able to pull it off :P. So you get a bit more security, but in turn lose some java conventions on the road. – Calon Mar 20 '14 at 14:06
  • If you use "getDomain()" in conjunction with "getName()", it's pretty secure for Windows at least compared to using System.getProperty("user.name"); – trilogy Jun 15 '22 at 15:39
7

Using JNA its simple:

String username = Advapi32Util.getUserName();
System.out.println(username);

Advapi32Util.Account account = Advapi32Util.getAccountByName(username);
System.out.println(account.accountType);
System.out.println(account.domain);
System.out.println(account.fqn);
System.out.println(account.name);
System.out.println(account.sidString);

https://github.com/java-native-access/jna

ANTARA
  • 810
  • 1
  • 13
  • 20
  • 1
    This doesn't work if you are logged in as a domain user but there is also a local user of the same name. getAccountByName will return information for the local user. – David Jan 12 '18 at 11:22
2

The 'set Username="Username" ' is a temporary override that only exists as long as the cmd windows is still up, once it is killed off, the variable loses value. So i think the

System.getProperty("user.name");

is still a short and precise code to use.

Newtoxton
  • 186
  • 2
  • 7
1

System.getenv().get("USERNAME"); - works on windows !

In environment properties you have the information you need about computer and host! I am saying again! Works on WINDOWS !

Dragos Roban
  • 479
  • 2
  • 11
  • 20
0

Below is a solution for WINDOWS ONLY

In cases where the application (like Tomcat) is started as a windows service, the System.getProperty("user.name") or System.getenv().get("USERNAME") return the user who started the service and not the current logged in user name.

Also in Java 9 the NTSystem etc classes will not be accessible

So workaround for windows: You can use wmic, so you have to run the below command

wmic ComputerSystem get UserName

If available, this will return output of the form:

UserName
{domain}\{logged-in-user-name}

Note: For windows you need to use cmd /c as a prefix, so below is a crude program as an example:

    Process exec = Runtime.getRuntime().exec("cmd /c wmic ComputerSystem get UserName".split(" "));
    System.out.println(exec.waitFor());
    try (BufferedReader bw = new BufferedReader(new InputStreamReader(exec.getInputStream()))) {
        System.out.println(bw.readLine() + "\n" + bw.readLine()+ "\n" + bw.readLine());
    }
Deepak
  • 3,648
  • 1
  • 22
  • 17
  • com.sun.security.auth.module.NTSystem still exists in Java17 .. however, UnixSystem and SolarisSystem are not. – trilogy Jun 15 '22 at 16:01
0

I tested in linux centos

Map<String, String> env = System.getenv();   
for (String envName : env.keySet()) { 
 System.out.format("%s=%s%n", envName, env.get(envName)); 
}

System.out.println(env.get("USERNAME")); 
dheeraj kumar
  • 419
  • 4
  • 6