How to handle java passwd reading when System.cons

2019-04-29 13:08发布

问题:

I'm writing a commandline program that prompts for a passwd and I don't want it to do local echo of the password characters. After some searches, I have stumbled upon System.console().readPassword(), which seems great, except when dealing with pipes in Unix. So, my example program (below) works fine when I invoke it as:

% java PasswdPrompt

but fails with Console == null when I invoke it as

% java PasswdPrompt | less

or

% java PasswdPrompt < inputfile

IMHO, this seems like a JVM issue, but I can't be the only one who has run into this problem so I have to imagine there are some easy solutions.

Any one?

Thanks in advance

import java.io.Console;

public class PasswdPrompt {
    public static void main(String args[]) {
        Console cons = System.console();
        if (cons == null) {
            System.err.println("Got null from System.console()!; exiting...");
            System.exit(1);
        }
        char passwd[] = cons.readPassword("Password: ");
        if (passwd == null) {
            System.err.println("Got null from Console.readPassword()!; exiting...");
            System.exit(1);
        }
        System.err.println("Successfully got passwd.");
    }
}

回答1:

From the Java documentation page :

If System.console returns NULL, then Console operations are not permitted, either because the OS doesn't support them or because the program was launched in a noninteractive environment.

The problem is most likely because using a pipe falls out of "interactive" mode and using an input file uses that as System.in, thus no Console.

** UPDATE **

Here's a quick fix. Add these lines at then end of your main method :

if (args.length > 0) {
   PrintStream out = null;
   try {
      out = new PrintStream(new FileOutputStream(args[0]));
      out.print(passwd);
      out.flush();
   } catch (Exception e) {
      e.printStackTrace();
   } finally {
      if (out != null) out.close();
   }
}

And invoke your application like

$ java PasswdPrompt .out.tmp; less .out.tmp; rm .out.tmp

However, your prompted password will reside in plaintext (though hidden) file until the command terminates.



回答2:

So, for some reason, when System.console() returns null, terminal echo is always off, so my problem becomes trivial. The following code works exactly as I wanted. Thanks for all the help.

import java.io.*;


public class PasswdPrompt {
    public static void main(String args[]) throws IOException{
        Console cons = System.console();
        char passwd[];
        if (cons == null) {
            // default to stderr; does NOT echo characters... not sure why
            System.err.print("Password: ");
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                                            System.in));
            passwd= reader.readLine().toCharArray();
        }
        else {
            passwd = cons.readPassword("Password: ");
        }
        System.err.println("Successfully got passwd.: " + String.valueOf(passwd));
    }

}