Path: blob/master/src/java.base/share/classes/sun/security/util/ConsoleCallbackHandler.java
41159 views
/*1* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.util;2627import javax.security.auth.callback.Callback;28import javax.security.auth.callback.CallbackHandler;29import javax.security.auth.callback.ConfirmationCallback;30import javax.security.auth.callback.NameCallback;31import javax.security.auth.callback.PasswordCallback;32import javax.security.auth.callback.TextOutputCallback;33import javax.security.auth.callback.UnsupportedCallbackException;3435import java.io.BufferedReader;36import java.io.IOException;37import java.io.InputStreamReader;3839/**40* A {@code CallbackHandler} that prompts and reads from the command line41* for answers to authentication questions.42*/43public class ConsoleCallbackHandler implements CallbackHandler {4445/**46* Creates a callback handler that prompts and reads from the47* command line for answers to authentication questions.48*/49public ConsoleCallbackHandler() { }5051/**52* Handles the specified set of callbacks.53*54* @param callbacks the callbacks to handle55* @throws IOException if an input or output error occurs.56* @throws UnsupportedCallbackException if the callback is not an57* instance of NameCallback or PasswordCallback58*/59public void handle(Callback[] callbacks)60throws IOException, UnsupportedCallbackException61{62ConfirmationCallback confirmation = null;6364for (int i = 0; i < callbacks.length; i++) {65if (callbacks[i] instanceof TextOutputCallback) {66TextOutputCallback tc = (TextOutputCallback) callbacks[i];6768String text;69switch (tc.getMessageType()) {70case TextOutputCallback.INFORMATION:71text = "";72break;73case TextOutputCallback.WARNING:74text = "Warning: ";75break;76case TextOutputCallback.ERROR:77text = "Error: ";78break;79default:80throw new UnsupportedCallbackException(81callbacks[i], "Unrecognized message type");82}8384String message = tc.getMessage();85if (message != null) {86text += message;87}88if (text != null) {89System.err.println(text);90}9192} else if (callbacks[i] instanceof NameCallback) {93NameCallback nc = (NameCallback) callbacks[i];9495if (nc.getDefaultName() == null) {96System.err.print(nc.getPrompt());97} else {98System.err.print(nc.getPrompt() +99" [" + nc.getDefaultName() + "] ");100}101System.err.flush();102103String result = readLine();104if (result.isEmpty()) {105result = nc.getDefaultName();106}107108nc.setName(result);109110} else if (callbacks[i] instanceof PasswordCallback) {111PasswordCallback pc = (PasswordCallback) callbacks[i];112113System.err.print(pc.getPrompt());114System.err.flush();115116pc.setPassword(Password.readPassword(System.in, pc.isEchoOn()));117118} else if (callbacks[i] instanceof ConfirmationCallback) {119confirmation = (ConfirmationCallback) callbacks[i];120121} else {122throw new UnsupportedCallbackException(123callbacks[i], "Unrecognized Callback");124}125}126127/* Do the confirmation callback last. */128if (confirmation != null) {129doConfirmation(confirmation);130}131}132133/* Reads a line of input */134private String readLine() throws IOException {135String result = new BufferedReader136(new InputStreamReader(System.in)).readLine();137if (result == null) {138throw new IOException("Cannot read from System.in");139}140return result;141}142143private void doConfirmation(ConfirmationCallback confirmation)144throws IOException, UnsupportedCallbackException145{146String prefix;147int messageType = confirmation.getMessageType();148switch (messageType) {149case ConfirmationCallback.WARNING:150prefix = "Warning: ";151break;152case ConfirmationCallback.ERROR:153prefix = "Error: ";154break;155case ConfirmationCallback.INFORMATION:156prefix = "";157break;158default:159throw new UnsupportedCallbackException(160confirmation, "Unrecognized message type: " + messageType);161}162163class OptionInfo {164String name;165int value;166OptionInfo(String name, int value) {167this.name = name;168this.value = value;169}170}171172OptionInfo[] options;173int optionType = confirmation.getOptionType();174switch (optionType) {175case ConfirmationCallback.YES_NO_OPTION:176options = new OptionInfo[] {177new OptionInfo("Yes", ConfirmationCallback.YES),178new OptionInfo("No", ConfirmationCallback.NO)179};180break;181case ConfirmationCallback.YES_NO_CANCEL_OPTION:182options = new OptionInfo[] {183new OptionInfo("Yes", ConfirmationCallback.YES),184new OptionInfo("No", ConfirmationCallback.NO),185new OptionInfo("Cancel", ConfirmationCallback.CANCEL)186};187break;188case ConfirmationCallback.OK_CANCEL_OPTION:189options = new OptionInfo[] {190new OptionInfo("OK", ConfirmationCallback.OK),191new OptionInfo("Cancel", ConfirmationCallback.CANCEL)192};193break;194case ConfirmationCallback.UNSPECIFIED_OPTION:195String[] optionStrings = confirmation.getOptions();196options = new OptionInfo[optionStrings.length];197for (int i = 0; i < options.length; i++) {198options[i] = new OptionInfo(optionStrings[i], i);199}200break;201default:202throw new UnsupportedCallbackException(203confirmation, "Unrecognized option type: " + optionType);204}205206int defaultOption = confirmation.getDefaultOption();207208String prompt = confirmation.getPrompt();209if (prompt == null) {210prompt = "";211}212prompt = prefix + prompt;213if (!prompt.isEmpty()) {214System.err.println(prompt);215}216217for (int i = 0; i < options.length; i++) {218if (optionType == ConfirmationCallback.UNSPECIFIED_OPTION) {219// defaultOption is an index into the options array220System.err.println(221i + ". " + options[i].name +222(i == defaultOption ? " [default]" : ""));223} else {224// defaultOption is an option value225System.err.println(226i + ". " + options[i].name +227(options[i].value == defaultOption ? " [default]" : ""));228}229}230System.err.print("Enter a number: ");231System.err.flush();232int result;233try {234result = Integer.parseInt(readLine());235if (result < 0 || result > (options.length - 1)) {236result = defaultOption;237} else {238result = options[result].value;239}240} catch (NumberFormatException e) {241result = defaultOption;242}243244confirmation.setSelectedIndex(result);245}246}247248249