articles

Home / DeveloperSection / Articles / Java I/O: The Console Class

Java I/O: The Console Class

Samuel Fernandes 1626 26-May-2016

So far we have been using System.out to print messages to the console. Java SE 6 added a Console class to enhance and simplify command-line applications. It provides a C-style printf method that allows the use of format specifiers in the output string. Most importantly, it provides a method for reading passwords that disables console echo and returns a char array. Both these features are very important for ensuring security, as explained shortly.

No public constructor is available for the Console class. We can obtain an instance of Console by calling the console method of the System class. It returns us a reference to the Console object.

When we start the JVM from a command line, the console typically will be connected to the keyboard and the display, unless we have explicitly redirected these to other streams.

A Console might not be available under some situations. For example, if we execute the program statement System.console() in a NetBeans IDE (as well as in some other IDEs), it returns a null object for the Console, because NetBeans provides its own window for the console output. Likewise, if a JVM is started by a background job scheduler, it will typically not have a console.

The program shown here illustrates the use of the Console class. This program provides a secure login for a console-based application.

Program code

public class ConsoleApp {
                          private static final int MAX_LOGINS = 3;
 
                          public static void main(String[] args) {
                                    ConsoleApp app = new ConsoleApp();
                                    if (app.login()) {
                                                System.out.println("Thanks for logging in!");
                                    } else {
                                                System.out.println("Login failed!");
                                    }
                          }
 
                          private boolean login() {
                                    Console console = System.console();
                                    boolean isAuthenticated = false;
                                    if (console != null) {
                                                int count = 0;
                                                do {
                                                          char[] pwd = console.readPassword("[%s]", "Password:");
                                                           isAuthenticated = authenticate(pwd);
 
                                                                  // delete password from memory
                                                            Arrays.fill(pwd, ' ');
                                                            console.writer().write("\n");
                                                } while (!isAuthenticated && ++count < MAX_LOGINS);
                                    }
                                    return isAuthenticated;
                          }
 
                          private boolean authenticate(char[] passwd) {
                                    char[] secret = { 'M', ‘i’, ‘N’, ‘D’, ‘S’, ‘T’, ‘I’, ‘C’, ‘K’};
                                    if (java.util.Arrays.equals(passwd, secret)) {
                                                java.util.Arrays.fill(passwd, ' ');
                                                System.out.println("Authenticated\n");
                                                return true;
                                    } else {
                                                System.out.println("Authentication failed\n");
                                    }
                                    return false;
                          }
Explanations:

The main method creates an application instance and calls its login method before proceeding with the rest of the application’s functionality. The login method obtains the Console object by calling the console method of the System class:

Console console = System.console();

This object would be null if we run the application in NetBeans. In such a situation, we return false to the caller, which eventually terminates the application. We give three attempts to the user to enter the correct password. We read the password using the following statement:

char[] pwd = console.readPassword("[%s]", "Password:");

The preceding statement prints a prompt on the user’s console. The user-entered password is returned in the pwd character array. The authenticate method verifies the entered password with the system-stored password. Immediately after obtaining the result of this verification, we clear the character buffer with spaces:

Arrays.fill(pwd, ' ');

Now, two important things are happening here in regard to security.

·   First, the readPassword does not echo the characters typed; therefore, even if someone is looking over the user’s shoulder, the password is not revealed.

·   Second, the password is cleared from system memory immediately after its use. If we had stored this password in a String variable, nullifying the String object still might have left the password string in the pool, thus making it available to a malicious resident program. Clearing the character buffer ensures that the password is removed from system memory.

The idea behind the character array is that a primitive array can be deterministically cleared from memory, as opposed to a String or other container, thereby minimizing the time the sensitive data is active in the memory.

Finally, let’s look at the implementation of the authenticate method. This is just a stub. The method stores the secret password in a character array. In reality, we would store an encrypted password, or rather the hash of the password, in a database. The equals method of the Arrays class compares its two arguments for equality. Depending on the outcome of this comparison, we print an appropriate message to the caller and return a boolean value to the caller.


Updated 18-Dec-2017

Leave Comment

Comments

Liked By