How to use Scanner to read silently from STDIN in Java? - java

I want to make a Java program that reads a Password from STDIN silently. I mean, without outputting any pressed chars to the terminal and keeping it hidden from commandline history and the operating system processlist ps.

The class java.io.Console may be useful:
System.console().readPassword();
This reads a sequence of chars from the console, without echoing anything.
Note that it only works when you launch your java application with a real console. Otherwise, System.console() returns null.

A less secure option to get the password via STDIN that works with background jobs, virtual consoles, and normal consoles:
This is more compatible and less secure, it should work with your virtual console in your IDE, for background processes that don't have a TTY, and normal consoles. When a console is not found, it falls back to use a BufferedReader which will expose the password to screen as the user types it in some cases.
Java Code:
import java.io.*;
public class Runner {
public static void main(String[] args) {
String username = "Eric";
try {
ReadMyPassword r = new ReadMyPassword();
char[] password = r.readPassword(
"Hey %s, enter password to arm the nuclear wessels>", username);
System.out.println("Exposing the password now: '" +
new String(password) + "'");
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ReadMyPassword{
public char[] readPassword(String format, Object... args)
throws IOException {
if (System.console() != null)
return System.console().readPassword(format, args);
return this.readLine(format, args).toCharArray();
}
private String readLine(String format, Object... args) throws IOException {
if (System.console() != null) {
return System.console().readLine(format, args);
}
System.out.print(String.format(format, args));
BufferedReader reader = new BufferedReader(new InputStreamReader(
System.in));
return reader.readLine();
}
}
Here's what it looks like through through the Eclipse virtual console:
Hey Eric, enter password to arm the nuclear wessels>12345
Exposing the password now: '12345'
Program Sisko 197 ready for implementation on your command
Here's what it looks like through the normal console.
el#apollo:/home/el/bin$ java Runner
Hey Eric, enter password to arm the nuclear wessels>
Exposing the password now: 'abcdefg'
Program Sisko 197 ready for implementation on your command
el#apollo:/home/el/bin$

You might want to give java.io.Console a look
It has a readPassword method which "Reads a password or passphrase from the console with echoing disabled".

Most secure option for Java to get a password with STDIN:
This demonstration is with Java on an Ubuntu 12.10 terminal. Grabbing the password with STDIN is a good idea security wise, since the password is not exposed to command line history or within the processlist with ps. The password letters typed are thrown away and not stored.
Java Code:
public class Runner {
public static void main(String[] args) {
System.out.print("Enter password: ");
String secretpassword = new String(System.console().readPassword());
System.out.println("Here we expose our password to STDOUT: "
+ secretpassword);
//Put maximum levels of encapsulation and security on this
//secretpassword variable. Destroy it in memory asap, don't leave it
//sitting around anywhere.
}
}
Conditions if you use the above code
If super high security is your top priority don't even store that password in a String. Encrypt it immediately after receiving it from the user. That way if some clever person scans the memory of your program, they won't find your plaintext password there.
If you try to run this program through a background job scheduler, then it is possible that System.console().readPassword() will return a NullPointerException which is a feature to enhance security. It denies access to shenanigans like virtual consoles and background tasks. If you want it to work right with virtual consoles see my other answer on this page.
If you try to run this code through an IDE like Eclipse, Netbeans or any other virtual console, then System.console().readPassword() will throw a NullPointerException because no real console is found, and the program will halt. This is a feature, not a bug.
What is looks like on the console:
el#apollo:/home/el/test$ java Runner
Enter password:
Here we expose our password to STDOUT: foobarpassword
el#apollo:/home/el/test$

Related

Looping a .next() in a while() loop gives NoSuchElementException in one compiler but not on another

I am a novice at coding but cannot understand why it runs fine on my machine, but when I upload my code I get a "NoSuchElementException" on line 19, "String command = keyboar.next();" I understand it has to do something with closing the scanner but I cannot figure out any other way to work it so it loops the print screen and input. Especially since it works fine when I run it on my machine.
Any insight is much appreciated here
import java.util.Scanner;
public class example1
{
public static void main(String[] args)
{
System.out.println("Enter an ending value");
Scanner keyboard = new Scanner(System.in);
int input;
input = keyboard.nextInt();
while(true){
System.out.println("Count up or down?");
String command = keyboard.next();
if (command.equalsIgnoreCase("up")) {
int one = 1;
int ten = 11;
int hund = 101;
while (one <= input) {
System.out.printf("%5d %4d %4d\n", one, ten, hund);
one++;
ten++;
hund++;
}
}
if (command.equalsIgnoreCase("down")) {
int neg = -input;
int one = -1;
int ten = 9;
int hund = 99;
while (one >= neg) {
System.out.printf("%5d %4d %4d\n", one, ten, hund);
one--;
ten--;
hund--;
}
}
}
}
}
You've created a scanner that reads from System.in. You don't close it anywhere, so I'm not sure why you wrote in your question that you feel it has something to do with that.
System.in does not represent the keyboard. It represents the java process's 'standard in' stream. If you just run java -jar foo.jar or whatnot on the command line (which is its own process, called the 'shell' - it'll be cmd.exe on windows, perhaps /bin/bash on linux. It's just an application, nothing special) - then that shell will decide that you intended to hook up the keyboard (technically, the 'terminal', which is usually virtualized, for example if you use ssh or other tools to remote your way onto another server, usually a physical keyboard isn't even connected to those things!).
But that's just because you started that process in a command line without explicitly specifying. If you double-click a jar on linux you probably won't get any terminal and nothing will be hooked up to standard in. If instead you start java -jar yourapp.jar <somefile.txt then bash will open the somefile.txt and set that up as the standard in.
The keyboard never runs out - you won't get a NoSuchElementException there.
But files run out. Given that you get this error when you 'upload' your application, clearly, something has been hooked up when whatever you uploaded it to runs your application that isn't the keyboard. It's probably a file, or at any rate, a limited stream.
You're asking for more tokens when there is nothing left to give.
Here's one obvious explanation:
This is homework or some coding exercise / coding competition.
You are uploading it to a grading server or competition testing server.
That server is (obviously - or you'd have to hire folks to type input data in over and over!) running your java app with the test data hooked up to System.in, and not an actual keyboard or even a virtualized one. Nobody is entering any keys to toss the test data at your app.
You have misunderstood the format of what the input is, so your application attempts to read more tokens than there actually are.
You can trivially reproduce this error yourself. First make a text file named 'test.txt', containing the string Hello and nothing more:
> cat test.txt
Hello
> cat Test.java
public class Test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println(in.next());
System.out.println(in.next());
}
}
> javac Test.java
> java Test <test.txt
NoSuchElementException
After all, this code tries to read 2 tokens from the standard input, which is that test file, which doesn't have 2 tokens. The same thing is happening in your setup.
SOLUTION: Reread the exercise description, you've misunderstood the inputs. For example, I bet the description says that a blank line means you need to exit the app, or if a command quit or exit comes in, or whatnot. Your app runs forever, it's highly unlikely homework / a coding exercise requires this.

How to block command prompt from showing my password while I'm inputting it to my java program [duplicate]

This question already has answers here:
Masking password input from the console : Java
(5 answers)
Closed 9 years ago.
So I have this application, where I read users input from command prompt, and when user is inputting his/her password, I would like to hide it such that everyone else cant see it like this:
Please enter your password below
this is password
I would like to show it like this:
Please enter your password below
****************
So is there any way of doing this in java console application?
Take a look at the Console class, it has readPassword()
Syntax:
public char[] readPassword(String fmt,Object... args)
Provides a formatted prompt, then reads a password or passphrase from the console with echoing disabled.
Parameters:
fmt - A format string as described in Format string syntax for the prompt text.
args - Arguments referenced by the format specifiers in the format string. If there are more arguments than format specifiers,
the extra arguments are ignored. The maximum number of arguments is
limited by the maximum dimension of a Java array as defined by the
Java Virtual Machine Specification.
Returns - A character array containing the password or passphrase read from the console, not including any line-termination
characters, or null if an end of stream has been reached.
Taken from the answer pointed in the comment:
import java.io.Console;
public class Main {
public void passwordExample() {
Console console = System.console();
if (console == null) {
System.out.println("Couldn't get Console instance");
System.exit(0);
}
console.printf("Testing password%n");
char passwordArray[] = console.readPassword("Enter your secret password: ");
console.printf("Password entered was: %s%n", new String(passwordArray));
}
public static void main(String[] args) {
new Main().passwordExample();
}
}
The thing to notice is that you are getting back a char[] and not a String. This is for security reasons and there is another great answer on this same topic on SO. You should destroy this char[] by overwriting it after your work is done. Strings can stay a longer time in memory till the GC collects them and this can be a security risk.
Run the example from the command line and not from an IDE. It may not work.

read output text on calling spawn.send()

I am new to ExpectJ Java programming. I downloaded jar's and able to do few send() and expect() methods. send() would fire a command on console and expect() would identify any prompt's so inputs can be provided. Expect only reads is there are prompts, and not other info. For example, if want to fire, spawn.send("ls") and get list of all file names and so certain action, is that possible?.
Is there way so I can read normal output of spawn.send("ls") for example, without expect which only captures prompts?
You can indeed capture the output stream:
It is one of the methods of the ExpectJ.Spawn class
I am also very new to Java, but I got the output, however, I am still struggling on getting the prompt recognized as I get extra control characters from Unix so do not trust what comes after the second System.out.println (the sh,expect part)
the output works fine, just set it in a variable if you want, or if you use swing, send it to a textarea with a listener.
BTW! if you know how to do the expect without these bloody control characters, 1m,34 [001 and so on, I welcome your input
import expectj.ExpectJ;
import expectj.Spawn;
public class myExpectinator {
public myExpectinator(){
}
public void connect(){
try {
ExpectJ ex = new ExpectJ(10);
Spawn sh = ex.spawn("10.10.10.10", 22, "name", "password");
System.out.println(sh.getCurrentStandardOutContents());
System.out.println(sh.getCurrentStandardErrContents());
sh.expect("~ $");
sh.send("ps\n");
System.out.println(sh.getCurrentStandardOutContents());
//sh.expectClose();
sh.stop();
}
catch(Exception e) {
System.out.println(e);
}
}
}

Console class in java Exception in reading password

i am trying to use Console class in java. with this code
import java.io.Console;
public class ConsoleClass {
public static void main(String[] args){
Console c=System.console();
char[] pw;
pw=c.readPassword("%s","pw :");
for(char ch:pw){
c.format("%c",ch);
}
c.format("\n");
MyUtility mu =new MyUtility();
while(true){
String name=c.readLine("%s", "input?: ");
c.format("output: %s \n",mu.doStuff(name));
}
}
}
class MyUtility{
String doStuff(String arg1){
return "result is " +arg1;
}
}
here i am getting NullPointerException when i tried to run in netbeans but i am not getting any Exception when tried to run in cmd with out netbeans IDE.Why?
static Console console()
Returns the unique Console object associated with the current Java virtual machine, if any.
If any.
http://download.oracle.com/javase/6/docs/api/java/lang/System.html
Consoles are typically associated with processes that run independently of frameworks. They are a means of interfacing a process's standard input and output with a shell. If your classes are running as a component of a larger framework, the framework may own the console, and your program might not have a console at all.
There are other conditions and techniques to launch a program without a console. They are typically used when the destruction of the console is guaranteed to occur, but you want the program detached in such a manner that the console's destruction doesn't signal the program's termination.
As such, you cannot guarantee the existence of a console; but, if you are going to run your program in an environment where the console is likely to be present, you should take advantage of it.
System.console() returns a Console instance if a console is associated with the process. - Running under NetBeans you likely don't have an associated console.

Program output lost when passed through PsExec

(This is a question my coworker posted elsewhere, but I thought I'd post it here to see if I could hit a different audience.)
Hello all,
I'm testing the possibility of writing a small java application the will use Psexec to kick off remote jobs. In the course of testing binding the stdin and stdout of a java program to psexec I came across an odd bug.
My test program is a basic echo program. It starts a thread to read from stdin and then pipes the read output directly back to stdout. When run on the local machine, not from psexec, it works beautifully. Exactly as it should.
However, when I call it from PsExec the first time the input is piped directly into stdout it is lost. What makes the bug really bizzare is that it is only the first time the input is piped directly into stdout that it is lost. If the input String is appended to another string it works fine. Either a String literal or a String variable. However, if the input String is sent directly to stdout it doesn't go through. The second time it is sent to stdout it goes through fine - and everytime there after.
I'm at a complete loss as to what's going on here. I've tried to test for every possible bug I can think of. I'm out of ideas. Did I miss one or is this just something inside psexec?
Here is the code in question, it's in three classes (one of which implements an interface which is a single function interace).
The Main class:
public class Main {
public static void main(String[] args) {
System.out.println("Starting up.");
CReader input = new CReader(new BufferedReader(
new InputStreamReader(System.in)));
CEcho echo = new CEcho();
input.addInputStreamListener(echo);
input.start();
System.out.println("Successfully started up. Awaiting input.");
}
}
The CReader class which is the thread that reads from stdin:
public class CReader extends Thread {
private ArrayList<InputStreamListener> listeners =
new ArrayList<InputStreamListener>();
private boolean exit = false;
private Reader in;
public CReader(Reader in) {
this.in = in;
}
public void addInputStreamListener(InputStreamListener listener) {
listeners.add(listener);
}
public void fireInputRecieved(String input) {
if(input.equals("quit"))
exit = true;
System.out.println("Input string has made it to fireInputRecieved: "
+ input);
for(int index = 0; index < listeners.size(); index++)
listeners.get(index).inputRecieved(input);
}
#Override
public void run() {
StringBuilder sb = new StringBuilder();
int current = 0, last = 0;
while (!exit) {
try {
current = in.read();
}
catch (IOException e) {
System.out.println("Encountered IOException.");
}
if (current == -1) {
break;
}
else if (current == (int) '\r') {
if(sb.toString().length() == 0) {
// Extra \r, don't return empty string.
continue;
}
fireInputRecieved(new String(sb.toString()));
sb = new StringBuilder();
}
else if(current == (int) '\n') {
if(sb.toString().length() == 0) {
// Extra \n, don't return empty string.
continue;
}
fireInputRecieved(new String(sb.toString()));
sb = new StringBuilder();
}
else {
System.out.println("Recieved character: " + (char)current);
sb.append((char) current);
last = current;
}
}
}
}
The CEcho class, which is the class that pipes it back to stdout:
public class CEcho implements InputStreamListener {
public void inputRecieved(String input) {
System.out.println("\n\nSTART INPUT RECIEVED");
System.out.println("The input that has been recieved is: "+input);
System.out.println("It is a String, that has been copied from a " +
"StringBuilder's toString().");
System.out.println("Outputting it cleanly to standard out: ");
System.out.println(input);
System.out.println("Outputting it cleanly to standard out again: ");
System.out.println(input);
System.out.println("Finished example outputs of input: "+input);
System.out.println("END INPUT RECIEVED\n\n");
}
}
And finally, here is the program output:
>psexec \\remotecomputer "C:\Program Files\Java\jre1.6.0_05\bin\java.exe" -jar "C:\Documents and Settings\testProram.jar"
PsExec v1.96 - Execute processes remotely
Copyright (C) 2001-2009 Mark Russinovich
Sysinternals - www.sysinternals.com
Starting up.
Successfully started up. Awaiting input.
Test
Recieved character: T
Recieved character: e
Recieved character: s
Recieved character: t
Input string has made it to fireInputRecieved: Test
START INPUT RECIEVED
The input that has been recieved is: Test
It is a String, that has been copied from a StringBuilder's toString().
Outputting it cleanly to standard out:
Outputting it cleanly to standard out again:
Test
Finished example outputs of input: Test
END INPUT RECIEVED
have you tried redirecting the output into a file ( java... >c:\output.txt )? this way you could doublecheck if everything is going into stdout and maybe just getting eaten by psexec
PsExec is eating the output. Next interesting thing might be where it's eating the output. You could check this by getting a copy of Wireshark and checking whether the output in question is traversing the network or not. If it's not, then it's being eaten on the remote side. If it is, it's being eaten locally.
Not that I'm really sure where to go from there, but collecting more information certainly seems like a good path to be following...
I was having the same issue and tried multiple combinations of redirects.
This is what worked:
processBuilder.redirectErrorStream(true);
processBuilder.redirectOutput(Redirect.PIPE);
processBuilder.redirectInput(Redirect.INHERIT);
final Process process = processBuilder.start();
// Using Apache Commons IOUtils to get output in String
StringWriter writer = new StringWriter();
IOUtils.copy(process.getInputStream(), writer, StandardCharsets.UTF_8);
String result = writer.toString();
logger.info(result);
final int exitStatus = process.waitFor();
The Redirect.INHERIT for processBuilder.redirectInput got me the missing remote command output.
Is System.out not configured for autoflush? After the first print try System.out.flush() and see if the first line appears without more lines being printed.
(oh yeah, seriously, it is "RECEIVED", not "RECIEVED".)
OK, I've been thinking about this over the weekend and I since you are jumping from machine to machine I wonder if maybe there is a CharSet issue? Maybe it is eating the string the first time and dealing with a different code page or character set issue? Java is 16bit characters normally and windows is either 8bit with code pages or utf-8 these days.
Any chance the local and remote machines have different default character sets? If you are sending localized data over the net it might misbehave.
What I see when running psexec is that it spawns a child window to do the work but doesnt return that program's output to it's console window. I would suggest using WMI or some form of windows process API framework to gain a level of control you appear to lack with psexec. Surely java has an equivalent to .Net's System.Diagnotics.Process class.
Maybe you could try passing a copy of input to your listeners:
public void fireInputRecieved(String input) {
if(input.equals("quit"))
exit = true;
String inputCopy = new String(input);
System.out.println("Input string has made it to fireInputRecieved: "
+ input);
for(int index = 0; index < listeners.size(); index++)
listeners.get(index).inputRecieved(inputCopy);
}
I had similar problems with listeners where a passed variable would end up empty unless I did pass an explicit copy of it.
I don't necessarily have an answer, but some comments may prove helpful.
The "pass a copy" idea shouldn't matter, since your output successfully prints the string twice before the failure, then succeeds again afterward.
auto-flush shouldn't matter either, as you've already mentioned
Niko's suggestion has some merit, for diagnostic purposes. Mixed with Mark's suggestion, it makes me wonder if there aren't some invisible control characters getting involved somewhere. What if you printed the characters byte values as a diagnostic step?
You know that the value is "Test" (at least in the output you gave us). What happens if you pass "Test" directly to the failing printLn statement?
In situations like this, you want to gain as much information as possible. Insert breakpoints and analyze characters. Send the bytes to files and open them in hex editors. Do whatever you can to trace things as accurately and as precisely as possible.
Come up with weird test scenarios and try them, even if they shouldn't possibly help. You never know what good idea you might have while analyzing the results of the hopeless idea.
I'd guess that there is a bogus byte in there prefacing the T. According to JavaDocs, an InputStreamReader will read one or more bytes, and decode them into characters.
You could have an escape sequence or spurious byte in there, masquerading as a multibyte character.
Quick check - see if "current" is ever > 128 or < 33.
What if you used a CharArrayReader to get individual bytes, without any charset translation?
The theory is that during the first attempt to output the String using println, it's sending an escape character of some sort, eating the rest of the string. During later prints, either Java or the network pipe are handling or removing it, since it previously got that escape sequence, perhaps changing the handling in some way.
As an unrelated nit, sb.toString() returns a new String, so it's unnecessary to call "new String(sb.toString())"
Same issue here, I'm going through this post again and again these days, hoping I can find some solution. Then I decide I should give up psexec and find some alternative. So this is the thing: PAExec. Works perfect for getting command output.
How are you executing PsExec? My suspicion is that this is some code within PsExec which is actually doing echo suppression, possibly for the purposes of protecting a password. One way to test this hypothesis would be to change this code:
System.out.println("Outputting it cleanly to standard out: ");
System.out.println(input);
System.out.println("Outputting it cleanly to standard out again: ");
System.out.println(input);
to this:
System.out.println("Outputting it cleanly to standard out: ");
System.out.print(' ');
System.out.println(input);
System.out.println("Outputting it cleanly to standard out again: ");
System.out.println(input);
...thereby causing the output to be (if I'm right):
Outputting it cleanly to standard out:
Test
Outputting it cleanly to standard out again:
Test
Finished example outputs of input: Test
In particular, it's noticeable that the apparently-suppressed line is the first line which consists solely of Test - which is exactly the text you've just sent to the remote system. This sounds like PsExec attempting to suppress a remote system which is echoing its input in addition to producing its own output.
Is the password of the user on the remote machine perhaps Test? Are you using PsExec's -p parameter? Are you specifying -i?
I am dealing with this same issue and I am wondering if it has to do with how the cmd window and pipes in windows work while you don't have a true windowed session. The suppressed output happens when any new process is spawned. You would think that if you spawn a process that the stdout/stderr/stdin would be inherited from the process that spawned it; after all that is what happens if you spawn the process from a normal cmd window and the output from the new process is piped back to your own console. However if somewhere in the inheritance of the pipes something were to go wrong, like say not passing a WINDOW.GUI object because there is no physical window, windows doesn't let the stdin/stdout/stdin to be inherited. Can any one do some investigation or open a windows support ticket for this?
Seems no easy solution. My work-around in a recent project is using paexec.exe product. It captures output/error easily in JAVA(java-8), but hangs up upon completion of the remote command execution. When running this inside a server on the hosted machine, I have to spurn a new child JVM process to run paexec.exe and force kill it via its PID upon completion in order to release all the resources.
If anyone has better solution, please post it.

Categories