20

I hit this eclipse bug, where System.console() is not available for Java application launches. I have a small Java app that also requires a password to be entered that is only started from within the IDE. Is there any other way to safely read a password (meaning not displaying it on the console) from the console with only using JDK classes?

EDIT:
I know of System.in, but that is displaying the inputed characters in the console and is therefore not safe.

EDIT2:
I also want to note that one can create a batch file under windows or a small bash script under linux/unix in the project. By openening this file in eclipse with the system default editor, it will be started in a new console window where System.console() is available. This way you can start the application from within eclipse. but the project has to be built first, so that the binaries exist.

SpaceTrucker
  • 13,377
  • 6
  • 60
  • 99
  • 1
    I would view this as an excellent learning opportunity to see if you can create a small Java app without Eclipse, using only javac and maybe ant. It's easier than you think! – jonvuri Mar 01 '13 at 14:15
  • 1
    @jrajav This is more of a security question, not a simple learning question. – SpaceTrucker Mar 01 '13 at 14:24
  • 1
    I don't think there's a really good way to hide password on eclipse console. But, do you really need to mask passwords on eclipse console? Eclipse console is used only by the developers. Once you deploy your program, I assume it will run on JVM installed on the end-user's OS. – wns349 Mar 01 '13 at 14:28
  • 1
    @wns349 The app won't be deployed anywhere. It's just a small app to do a repeated job for us devs. But usually devs are sitting together at one desk. – SpaceTrucker Mar 01 '13 at 14:30

4 Answers4

5

Maybe instead of console try using dialog with JPasswordField. Here is example from http://blogger.ziesemer.com/2007/03/java-password-dialog.html.

final JPasswordField jpf = new JPasswordField();
JOptionPane jop = new JOptionPane(jpf, JOptionPane.QUESTION_MESSAGE,
        JOptionPane.OK_CANCEL_OPTION);
JDialog dialog = jop.createDialog("Password:");
dialog.addComponentListener(new ComponentAdapter() {
    @Override
    public void componentShown(ComponentEvent e) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                jpf.requestFocusInWindow();
            }
        });
    }
});
dialog.setVisible(true);
int result = (Integer) jop.getValue();
dialog.dispose();
char[] password = null;
if (result == JOptionPane.OK_OPTION) {
    password = jpf.getPassword();
}
if (password != null)
    System.out.println("your password: " + new String(password));
Pshemo
  • 122,468
  • 25
  • 185
  • 269
3

If System.console() returns null, that means that there is no usable console as far as Java is concerned.

  • You can't use System.in because the chances are that it is not connected to a console.

  • Even if you could, there is no portable way to turn off echoing in Java.

  • You might be able to use Swing (or whatever) to pop up a window to ask for the password, but if the system is headless that won't work.


If you are prepared to do non-portable things, then (on Linux / UNIX) you could try opening "/dev/console" or "/dev/tty". And then you could use termios to put the tty driver into noecho mode. But you'll need to do at least some of this in native code.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • 3
    That is not true, there is a case where `System.getConsole()` returns `null` but `System.in` is not `null`, for example in this case: http://stackoverflow.com/questions/4203646/system-console-returns-null . – David Georg Reichelt Dec 17 '14 at 17:12
  • @DavidReichelt - Which answer are you referring to? – Stephen C Dec 17 '14 at 22:57
  • 1
    @DavidReichelt - Anyway, what you are saying is beside the point. `System.in` will *always* be non-null!!! (Unless you call `setIn(null)` ...) The point is whether `System.in` points to an interactive console that can be used in non-echo mode to *safely* read a password. – Stephen C Dec 17 '14 at 23:01
  • @StephenC: David Georg Reichelt was probably referring to this answer (in the referred question): https://stackoverflow.com/a/11199326/1796 My personal experience with gradle 4, IntelliJ IDEA, JDK8, is that System.console() is null but System.in is not null **AND** is connected to the console and I am able to read from it correctly. – Andrei Rînea Apr 28 '20 at 18:09
3

I ran into the same issue. (Dear Eclipse Community: Is it so hard to fix that bug?) As everyone else I need the IDE for dev/debug and standalone for running.

So I wrote this method:

private static String readPwd() throws IOException {
    Console c=System.console();
    if (c==null) { //IN ECLIPSE IDE
        System.out.print("Password: ");
        InputStream in=System.in;
        int max=50;
        byte[] b=new byte[max];

        int l= in.read(b);
        l--;//last character is \n
        if (l>0) {
            byte[] e=new byte[l];
            System.arraycopy(b,0, e, 0, l);
            return new String(e);
        } else {
            return null;
        }
    } else { //Outside Eclipse IDE
        return new String(c.readPassword("Password: "));
    }
}

Downside of this workaround is that in Eclipse you are going to see the password during the runtime of the program.

Frank
  • 31
  • 1
  • 3
    *"(Dear Eclipse Community: Is it so hard to fix that bug?)"* - This is not the Eclipse Community! If you want to tell them about this "bug", they have an issue tracker. But unless you have a practical solution for them to implement, you'd probably be wasting your breath ... – Stephen C Jan 22 '14 at 09:04
2

Similar to the answer given by @Pshemo, one could fall back to Swing:

final String passwd;
final String message = "Enter password";
if( System.console() == null ) { 
  final JPasswordField pf = new JPasswordField(); 
  passwd = JOptionPane.showConfirmDialog( null, pf, message, 
    JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE ) == JOptionPane.OK_OPTION 
      ? new String( pf.getPassword() ) : ""; 
} else 
  passwd = new String( System.console().readPassword( "%s> ", message ) );
krevelen
  • 361
  • 3
  • 11