/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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.apache.nifi.toolkit.tls.commandLine; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.nifi.security.util.KeystoreType; import org.apache.nifi.toolkit.tls.TlsToolkitMain; import org.apache.nifi.toolkit.tls.configuration.TlsConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base class with common CLI parsing functionality as well as arguments shared by multiple entry points */ public abstract class BaseCommandLine { private static final Logger logger = LoggerFactory.getLogger(BaseCommandLine.class); public static final String HELP_ARG = "help"; public static final String JAVA_HOME = "JAVA_HOME"; public static final String NIFI_TOOLKIT_HOME = "NIFI_TOOLKIT_HOME"; public static final String FOOTER = new StringBuilder(System.lineSeparator()).append("Java home: ") .append(System.getenv(JAVA_HOME)).append(System.lineSeparator()).append("NiFi Toolkit home: ").append(System.getenv(NIFI_TOOLKIT_HOME)).toString(); public static final String KEY_SIZE_ARG = "keySize"; public static final String KEY_ALGORITHM_ARG = "keyAlgorithm"; public static final String CERTIFICATE_AUTHORITY_HOSTNAME_ARG = "certificateAuthorityHostname"; public static final String DAYS_ARG = "days"; public static final String KEY_STORE_TYPE_ARG = "keyStoreType"; public static final String SIGNING_ALGORITHM_ARG = "signingAlgorithm"; public static final String DN_ARG = "dn"; public static final String DIFFERENT_KEY_AND_KEYSTORE_PASSWORDS_ARG = "differentKeyAndKeystorePasswords"; public static final String KEYSTORE = "keystore."; public static final String TRUSTSTORE = "truststore."; private final Options options; private final String header; private int keySize; private String keyAlgorithm; private String certificateAuthorityHostname; private String keyStoreType; private int days; private String signingAlgorithm; private boolean differentPasswordForKeyAndKeystore; public BaseCommandLine(String header) { this.header = System.lineSeparator() + header + System.lineSeparator() + System.lineSeparator(); this.options = new Options(); if (shouldAddDaysArg()) { addOptionWithArg("d", DAYS_ARG, "Number of days issued certificate should be valid for.", TlsConfig.DEFAULT_DAYS); } addOptionWithArg("T", KEY_STORE_TYPE_ARG, "The type of keyStores to generate.", getKeyStoreTypeDefault()); options.addOption("h", HELP_ARG, false, "Print help and exit."); addOptionWithArg("c", CERTIFICATE_AUTHORITY_HOSTNAME_ARG, "Hostname of NiFi Certificate Authority", TlsConfig.DEFAULT_HOSTNAME); addOptionWithArg("a", KEY_ALGORITHM_ARG, "Algorithm to use for generated keys.", TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM); addOptionWithArg("k", KEY_SIZE_ARG, "Number of bits for generated keys.", TlsConfig.DEFAULT_KEY_SIZE); if (shouldAddSigningAlgorithmArg()) { addOptionWithArg("s", SIGNING_ALGORITHM_ARG, "Algorithm to use for signing certificates.", TlsConfig.DEFAULT_SIGNING_ALGORITHM); } addOptionNoArg("g", DIFFERENT_KEY_AND_KEYSTORE_PASSWORDS_ARG, "Use different generated password for the key and the keyStore."); } protected String getKeyStoreTypeDefault() { return TlsConfig.DEFAULT_KEY_STORE_TYPE; } protected boolean shouldAddSigningAlgorithmArg() { return true; } protected boolean shouldAddDaysArg() { return true; } protected void addOptionWithArg(String arg, String longArg, String description) { addOptionWithArg(arg, longArg, description, null); } protected void addOptionNoArg(String arg, String longArg, String description) { options.addOption(arg, longArg, false, description); } protected void addOptionWithArg(String arg, String longArg, String description, Object defaultVal) { String fullDescription = description; if (defaultVal != null) { fullDescription += " (default: " + defaultVal + ")"; } options.addOption(arg, longArg, true, fullDescription); } public void printUsage(String errorMessage) { if (errorMessage != null) { System.out.println(errorMessage); System.out.println(); } HelpFormatter helpFormatter = new HelpFormatter(); helpFormatter.setWidth(160); helpFormatter.printHelp(TlsToolkitMain.class.getCanonicalName(), header, options, FOOTER, true); } protected <T> T printUsageAndThrow(String errorMessage, ExitCode exitCode) throws CommandLineParseException { printUsage(errorMessage); throw new CommandLineParseException(errorMessage, exitCode); } protected int getIntValue(CommandLine commandLine, String arg, int defaultVal) throws CommandLineParseException { try { return Integer.parseInt(commandLine.getOptionValue(arg, Integer.toString(defaultVal))); } catch (NumberFormatException e) { return printUsageAndThrow("Expected integer for " + arg + " argument. (" + e.getMessage() + ")", ExitCode.ERROR_PARSING_INT_ARG); } } /** * Returns the number of bits used when generating KeyPairs * * @return the number of bits used when generating KeyPairs */ public int getKeySize() { return keySize; } /** * Returns the algorithm used when generating KeyPairs * * @return the algorithm used when generating KeyPairs */ public String getKeyAlgorithm() { return keyAlgorithm; } /** * Returns the CA Hostname * * @return the CA Hostname */ public String getCertificateAuthorityHostname() { return certificateAuthorityHostname; } /** * Returns the type to use for KeyStores * * @return the type to use for KeyStores */ public String getKeyStoreType() { return keyStoreType; } /** * Returns the number of Certificates should be valid for * * @return the number of Certificates should be valid for */ public int getDays() { return days; } /** * Returns the signing algorithm to use for cryptographic operations * * @return the signing algorithm to use for cryptographic operations */ public String getSigningAlgorithm() { return signingAlgorithm; } /** * Returns true if different passwords should be used for KeyStore and individual Key entries * * @return true if different passwords should be used for KeyStore and individual Key entries */ public boolean differentPasswordForKeyAndKeystore() { return differentPasswordForKeyAndKeystore; } protected CommandLine doParse(String[] args) throws CommandLineParseException { CommandLineParser parser = new DefaultParser(); CommandLine commandLine; try { commandLine = parser.parse(options, args); if (commandLine.hasOption(HELP_ARG)) { return printUsageAndThrow(null, ExitCode.HELP); } certificateAuthorityHostname = commandLine.getOptionValue(CERTIFICATE_AUTHORITY_HOSTNAME_ARG, TlsConfig.DEFAULT_HOSTNAME); days = getIntValue(commandLine, DAYS_ARG, TlsConfig.DEFAULT_DAYS); keySize = getIntValue(commandLine, KEY_SIZE_ARG, TlsConfig.DEFAULT_KEY_SIZE); keyAlgorithm = commandLine.getOptionValue(KEY_ALGORITHM_ARG, TlsConfig.DEFAULT_KEY_PAIR_ALGORITHM); keyStoreType = commandLine.getOptionValue(KEY_STORE_TYPE_ARG, getKeyStoreTypeDefault()); if (KeystoreType.PKCS12.toString().equalsIgnoreCase(keyStoreType)) { logger.info("Command line argument --" + KEY_STORE_TYPE_ARG + "=" + keyStoreType + " only applies to keystore, recommended truststore type of " + KeystoreType.JKS.toString() + " unaffected."); } signingAlgorithm = commandLine.getOptionValue(SIGNING_ALGORITHM_ARG, TlsConfig.DEFAULT_SIGNING_ALGORITHM); differentPasswordForKeyAndKeystore = commandLine.hasOption(DIFFERENT_KEY_AND_KEYSTORE_PASSWORDS_ARG); } catch (ParseException e) { return printUsageAndThrow("Error parsing command line. (" + e.getMessage() + ")", ExitCode.ERROR_PARSING_COMMAND_LINE); } return commandLine; } /** * Parses the command line arguments * * @param args the command line arguments * @throws CommandLineParseException if the arguments cannot be parsed */ public void parse(String... args) throws CommandLineParseException { doParse(args); } }