All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.hadoop.cli.Keytool Maven / Gradle / Ivy

There is a newer version: 8.16.0
Show newest version
/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.elasticsearch.hadoop.cli;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import org.elasticsearch.hadoop.security.EsHadoopSecurityException;
import org.elasticsearch.hadoop.security.KeystoreWrapper;

public class Keytool {

    private static final String KEYSTORE_FILE_NAME = "esh.keystore";

    public static void main(String[] args) {
        System.exit(execute(new ConsolePrompt(), args));
    }

    public static int execute(Prompt console, String[] args) {
        Command command = null;
        String commandArg = null;
        boolean hasSTDIN = false;
        boolean force = false;
        for (int idx = 0; idx < args.length; idx++) {
            String arg = args[idx];
            if (arg.equals(FLAG_H) || arg.equals(FLAG_HELP)) {
                printUsage(console);
                return 0;
            } else if (hasSTDIN == false && (arg.equals(FLAG_STDIN))) {
                hasSTDIN = true;
            } else if (force == false && (arg.equals(FLAG_F) || arg.equals(FLAG_FORCE))) {
                force = true;
            } else if (command == null) {
                command = Command.byName(arg.toLowerCase());
                if (command == null) {
                    printUsage(console);
                    error(console, "Unknown command [" + arg + "]");
                    return 2;
                }
            } else if (command.hasArgs() && commandArg == null) {
                commandArg = arg;
            } else {
                printUsage(console);
                error(console, "Unexpected argument [" + arg + "]");
                return 3;
            }
        }
        if (command == null) {
            printUsage(console);
            error(console, "No command specified");
            return 1;
        }
        if (command.hasArgs && commandArg == null) {
            printUsage(console);
            error(console, "Settings name required for command [" + command.text + "]");
            return 4;
        }
        // If stdin is from a pipe, then the console will be null. Treat this like --stdin.
        hasSTDIN |= (System.console() == null);
        try {
            return new Keytool(console, command).run(commandArg, hasSTDIN, force);
        } catch (IOException e) {
            console.println("ERROR: " + e.getMessage());
            return 11;
        }
    }

    private static final String TBLFRMT = "%-15s%-19s%n";

    private static void printUsage(Prompt prompt) {
        prompt.println("A tool for managing settings stored in an ES-Hadoop keystore");
        prompt.println();
        prompt.println("Commands");
        prompt.println("--------");
        prompt.println(Command.CREATE.getText() + " - Creates a new elasticsearch keystore");
        prompt.println(Command.LIST.getText() + " - List entries in the keystore");
        prompt.println(Command.ADD.getText() + " - Add a setting to the keystore");
        prompt.println(Command.REMOVE.getText() + " - Remove a setting from the keystore");
        prompt.println();
        prompt.printf(TBLFRMT, "Option", "Description");
        prompt.printf(TBLFRMT, "------", "-----------");
        prompt.printf(TBLFRMT, FLAG_H + ", " + FLAG_HELP, "show help");
        prompt.printf(TBLFRMT, FLAG_F + ", " + FLAG_FORCE, "ignore overwriting warnings when adding to the keystore");
    }

    private static void error(Prompt prompt, String error) {
        prompt.println("ERROR: " + error);
    }

    private static final String FLAG_HELP = "--help";
    private static final String FLAG_H = "-h";

    private static final String FLAG_FORCE = "--force";
    private static final String FLAG_F = "-f";

    private static final String FLAG_STDIN = "--stdin";

    enum Command {
        CREATE("create", false),
        LIST("list", false),
        ADD("add", true),
        REMOVE("remove", true);

        private final String text;
        private final boolean hasArgs;

        Command(String text, boolean hasArgs) {
            this.text = text;
            this.hasArgs = hasArgs;
        }

        public String getText() {
            return text;
        }

        public boolean hasArgs() {
            return hasArgs;
        }

        private static Map lookup = new HashMap();

        static {
            lookup.put(CREATE.text, CREATE);
            lookup.put(LIST.text, LIST);
            lookup.put(ADD.text, ADD);
            lookup.put(REMOVE.text, REMOVE);
        }

        public static Command byName(String name) {
            return lookup.get(name);
        }
    }

    private final Prompt prompt;
    private final Command command;

    Keytool(Prompt prompt, Command command) {
        this.prompt = prompt;
        this.command = command;
    }

    /**
     * Run the program with the given arguments
     *
     * @param arg   Usually the name of the property to set. Can be empty for some commands
     * @param stdin Flag to state that the input should be read from stdin
     * @param force Flag to state that overwriting a key should be ignored
     * @return exit code
     */
    public int run(String arg, boolean stdin, boolean force) throws IOException {
        OutputStream outputStream = null;
        InputStream inputStream = null;
        KeystoreWrapper keystoreWrapper;
        try {
            switch (command) {
                case CREATE:
                    if (ksExists()) {
                        boolean proceed = promptYesNo("An es-hadoop keystore already exists. Overwrite? [y/N]");
                        if (proceed == false) {
                            prompt.println("Exiting without creating keystore");
                            return 0;
                        }
                    }
                    keystoreWrapper = KeystoreWrapper.newStore().build();
                    outputStream = openWrite();
                    keystoreWrapper.saveKeystore(outputStream);
                    return 0;
                case LIST:
                    if (!ksExists()) {
                        prompt.printf("ERROR: ES-Hadoop keystore not found. Use '%s' command to create one.%n", Command.CREATE.getText());
                        return 5;
                    }
                    inputStream = openRead();
                    keystoreWrapper = KeystoreWrapper.loadStore(inputStream).build();
                    for (String entry : keystoreWrapper.listEntries()) {
                        prompt.println(entry);
                    }
                    return 0;
                case ADD:
                    if (!ksExists()) {
                        prompt.printf("ERROR: ES-Hadoop keystore not found. Use '%s' command to create one.%n", Command.CREATE.getText());
                        return 5;
                    }
                    inputStream = openRead();
                    keystoreWrapper = KeystoreWrapper.loadStore(inputStream).build();
                    if (keystoreWrapper.containsEntry(arg) && force == false) {
                        boolean proceed = promptYesNo("Setting %s already exists. Overwrite? [y/N]", arg);
                        if (proceed == false) {
                            prompt.println("Exiting without modifying keystore");
                            return 0;
                        }
                    }
                    if (stdin) {
                        String data = prompt.readLine();
                        keystoreWrapper.setSecureSetting(arg, data);
                    } else {
                        char[] data = prompt.readPassword("Enter value for %s:", arg);
                        keystoreWrapper.setSecureSetting(arg, new String(data));
                        Arrays.fill(data, (char) 0);
                    }
                    outputStream = openWrite();
                    keystoreWrapper.saveKeystore(outputStream);
                    return 0;
                case REMOVE:
                    if (!ksExists()) {
                        prompt.printf("ERROR: ES-Hadoop keystore not found. Use '%s' command to create one.%n", Command.CREATE.getText());
                        return 5;
                    }
                    inputStream = openRead();
                    keystoreWrapper = KeystoreWrapper.loadStore(inputStream).build();
                    if (keystoreWrapper.containsEntry(arg) == false) {
                        prompt.printf("ERROR: Setting [%s] does not exist in the keystore.%n", arg);
                        return 6;
                    }
                    keystoreWrapper.removeSecureSetting(arg);
                    outputStream = openWrite();
                    keystoreWrapper.saveKeystore(outputStream);
                    return 0;
                default:
                    prompt.println("ERROR: Unsupported command " + command.getText());
                    return 7;
            }
        } catch (EsHadoopSecurityException ehse) {
            prompt.println("ERRORCould not load keystore file: " + ehse.getMessage());
            return 8;
        } catch (FileNotFoundException fnfe) {
            prompt.println("ERROR: Could not load keystore file: " + fnfe.getMessage());
            return 9;
        } catch (IOException ioe) {
            prompt.println("ERROR: " + ioe.getMessage());
            return 10;
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    private boolean promptYesNo(String msgFormat, Object... args) {
        while (true) {
            String response = prompt.readLine(msgFormat, args);
            if (response == null || response.isEmpty() || response.equalsIgnoreCase("n")) {
                return false;
            } else if (response.equalsIgnoreCase("y")) {
                return true;
            } else {
                prompt.printf("Did not understand answer '%s'%n", response);
            }
        }
    }

    protected boolean ksExists() {
        File file = new File(KEYSTORE_FILE_NAME);
        return file.exists();
    }

    protected InputStream openRead() throws FileNotFoundException {
        File file = new File(KEYSTORE_FILE_NAME);
        return new FileInputStream(file);
    }

    protected OutputStream openWrite() throws IOException {
        File file = new File(KEYSTORE_FILE_NAME);
        if (file.exists()) {
            // Ignore return value
            file.createNewFile();
        }
        return new FileOutputStream(file);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy