/* * 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.standalone; import org.apache.nifi.toolkit.tls.commandLine.CommandLineParseException; import org.apache.nifi.toolkit.tls.commandLine.ExitCode; import org.apache.nifi.toolkit.tls.configuration.InstanceDefinition; import org.apache.nifi.toolkit.tls.configuration.InstanceIdentifier; import org.apache.nifi.toolkit.tls.configuration.StandaloneConfig; import org.apache.nifi.toolkit.tls.configuration.TlsConfig; import org.apache.nifi.toolkit.tls.properties.NiFiPropertiesWriter; import org.apache.nifi.toolkit.tls.util.PasswordUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.internal.stubbing.defaultanswers.ForwardsInvocations; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.security.SecureRandom; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.function.Function; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; public class TlsToolkitStandaloneCommandLineTest { private SecureRandom secureRandom; private TlsToolkitStandaloneCommandLine tlsToolkitStandaloneCommandLine; @Before public void setup() { secureRandom = mock(SecureRandom.class); doAnswer(new ForwardsInvocations(new Random())).when(secureRandom).nextBytes(any(byte[].class)); tlsToolkitStandaloneCommandLine = new TlsToolkitStandaloneCommandLine(new PasswordUtil(secureRandom)); } @Test public void testHelp() { try { tlsToolkitStandaloneCommandLine.parse("-h"); fail("Expected usage and help exit"); } catch (CommandLineParseException e) { Assert.assertEquals(ExitCode.HELP, e.getExitCode()); } } @Test public void testUnknownArg() { try { tlsToolkitStandaloneCommandLine.parse("--unknownArg"); fail("Expected error parsing command line"); } catch (CommandLineParseException e) { assertEquals(ExitCode.ERROR_PARSING_COMMAND_LINE, e.getExitCode()); } } @Test public void testKeyAlgorithm() throws CommandLineParseException { String testKeyAlgorithm = "testKeyAlgorithm"; tlsToolkitStandaloneCommandLine.parse("-a", testKeyAlgorithm); assertEquals(testKeyAlgorithm, tlsToolkitStandaloneCommandLine.createConfig().getKeyPairAlgorithm()); } @Test public void testKeySizeArgNotInteger() { try { tlsToolkitStandaloneCommandLine.parse("-k", "badVal"); fail("Expected bad keysize exit code"); } catch (CommandLineParseException e) { assertEquals(ExitCode.ERROR_PARSING_INT_ARG, e.getExitCode()); } } @Test public void testKeySize() throws CommandLineParseException, IOException { int testKeySize = 4096; tlsToolkitStandaloneCommandLine.parse("-k", Integer.toString(testKeySize)); assertEquals(testKeySize, tlsToolkitStandaloneCommandLine.createConfig().getKeySize()); } @Test public void testSigningAlgorithm() throws CommandLineParseException, IOException { String testSigningAlgorithm = "testSigningAlgorithm"; tlsToolkitStandaloneCommandLine.parse("-s", testSigningAlgorithm); assertEquals(testSigningAlgorithm, tlsToolkitStandaloneCommandLine.createConfig().getSigningAlgorithm()); } @Test public void testSAN() throws CommandLineParseException, IOException { String dnsSAN = "nifi.apache.org"; tlsToolkitStandaloneCommandLine.parse("--subjectAlternativeNames", dnsSAN); assertEquals(dnsSAN, tlsToolkitStandaloneCommandLine.createConfig().getDomainAlternativeNames()); } @Test public void testDaysNotInteger() { try { tlsToolkitStandaloneCommandLine.parse("-d", "badVal"); } catch (CommandLineParseException e) { assertEquals(ExitCode.ERROR_PARSING_INT_ARG, e.getExitCode()); } } @Test public void testDays() throws CommandLineParseException { int testDays = 29; tlsToolkitStandaloneCommandLine.parse("-d", Integer.toString(testDays)); assertEquals(testDays, tlsToolkitStandaloneCommandLine.createConfig().getDays()); } @Test public void testKeyStoreType() throws CommandLineParseException { String testKeyStoreType = "testKeyStoreType"; tlsToolkitStandaloneCommandLine.parse("-T", testKeyStoreType); assertEquals(testKeyStoreType, tlsToolkitStandaloneCommandLine.getKeyStoreType()); } @Test public void testOutputDirectory() throws CommandLineParseException { String testPath = File.separator + "fake" + File.separator + "path" + File.separator + "doesnt" + File.separator + "exist"; tlsToolkitStandaloneCommandLine.parse("-o", testPath); assertEquals(testPath, tlsToolkitStandaloneCommandLine.createConfig().getBaseDir().getPath()); } @Test public void testHostnames() throws CommandLineParseException { String nifi1 = "nifi1"; String nifi2 = "nifi2"; tlsToolkitStandaloneCommandLine.parse("-n", nifi1 + " , " + nifi2); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(2, instanceDefinitions.size()); assertEquals(nifi1, instanceDefinitions.get(0).getHostname()); assertEquals(nifi2, instanceDefinitions.get(1).getHostname()); } @Test public void testNifiPropertiesFile() throws CommandLineParseException, IOException { tlsToolkitStandaloneCommandLine.parse("-f", TlsToolkitStandaloneTest.TEST_NIFI_PROPERTIES); assertEquals(TlsToolkitStandaloneTest.FAKE_VALUE, getProperties().get(TlsToolkitStandaloneTest.NIFI_FAKE_PROPERTY)); } @Test public void testNifiPropertiesFileDefault() throws CommandLineParseException, IOException { tlsToolkitStandaloneCommandLine.parse(); assertNull(getProperties().get(TlsToolkitStandaloneTest.NIFI_FAKE_PROPERTY)); } @Test public void testBadNifiPropertiesFile() { try { tlsToolkitStandaloneCommandLine.parse("-f", "/this/file/should/not/exist.txt"); fail("Expected error when unable to read file"); } catch (CommandLineParseException e) { assertEquals(ExitCode.ERROR_READING_NIFI_PROPERTIES, e.getExitCode()); } } @Test public void testNotSameKeyAndKeystorePassword() throws CommandLineParseException { tlsToolkitStandaloneCommandLine.parse("-g", "-n", TlsConfig.DEFAULT_HOSTNAME); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(1, instanceDefinitions.size()); assertNotEquals(instanceDefinitions.get(0).getKeyStorePassword(), instanceDefinitions.get(0).getKeyPassword()); } @Test public void testSameKeyAndKeystorePassword() throws CommandLineParseException { tlsToolkitStandaloneCommandLine.parse("-n", TlsConfig.DEFAULT_HOSTNAME); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(1, instanceDefinitions.size()); assertEquals(instanceDefinitions.get(0).getKeyStorePassword(), instanceDefinitions.get(0).getKeyPassword()); } @Test public void testSameKeyAndKeystorePasswordWithKeystorePasswordSpecified() throws CommandLineParseException { String testPassword = "testPassword"; tlsToolkitStandaloneCommandLine.parse("-S", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(1, instanceDefinitions.size()); assertEquals(testPassword, instanceDefinitions.get(0).getKeyStorePassword()); assertEquals(testPassword, instanceDefinitions.get(0).getKeyPassword()); } @Test public void testSameKeyAndKeystorePasswordWithKeyPasswordSpecified() throws CommandLineParseException { String testPassword = "testPassword"; tlsToolkitStandaloneCommandLine.parse("-K", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertNotEquals(instanceDefinitions.get(0).getKeyStorePassword(), instanceDefinitions.get(0).getKeyPassword()); assertEquals(1, instanceDefinitions.size()); assertEquals(testPassword, instanceDefinitions.get(0).getKeyPassword()); } @Test public void testKeyStorePasswordArg() throws CommandLineParseException { String testPassword = "testPassword"; tlsToolkitStandaloneCommandLine.parse("-S", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(1, instanceDefinitions.size()); assertEquals(testPassword, instanceDefinitions.get(0).getKeyStorePassword()); } @Test public void testMultipleKeystorePasswordArgs() throws CommandLineParseException { String testPassword1 = "testPassword1"; String testPassword2 = "testPassword2"; tlsToolkitStandaloneCommandLine.parse("-n", "nifi1,nifi2", "-S", testPassword1, "-S", testPassword2); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(2, instanceDefinitions.size()); assertEquals(testPassword1, instanceDefinitions.get(0).getKeyStorePassword()); assertEquals(testPassword2, instanceDefinitions.get(1).getKeyStorePassword()); } @Test public void testKeyPasswordArg() throws CommandLineParseException { String testPassword = "testPassword"; tlsToolkitStandaloneCommandLine.parse("-K", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(1, instanceDefinitions.size()); assertEquals(testPassword, instanceDefinitions.get(0).getKeyPassword()); } @Test public void testMultipleKeyPasswordArgs() throws CommandLineParseException { String testPassword1 = "testPassword1"; String testPassword2 = "testPassword2"; tlsToolkitStandaloneCommandLine.parse("-n", "nifi1,nifi2", "-K", testPassword1, "-K", testPassword2); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(2, instanceDefinitions.size()); assertEquals(testPassword1, instanceDefinitions.get(0).getKeyPassword()); assertEquals(testPassword2, instanceDefinitions.get(1).getKeyPassword()); } @Test public void testTruststorePasswordArg() throws CommandLineParseException { String testPassword = "testPassword"; tlsToolkitStandaloneCommandLine.parse("-P", testPassword, "-n", TlsConfig.DEFAULT_HOSTNAME); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(1, instanceDefinitions.size()); assertEquals(testPassword, instanceDefinitions.get(0).getTrustStorePassword()); } @Test public void testMultipleTruststorePasswordArgs() throws CommandLineParseException { String testPassword1 = "testPassword1"; String testPassword2 = "testPassword2"; tlsToolkitStandaloneCommandLine.parse("-n", "nifi1,nifi2", "-P", testPassword1, "-P", testPassword2); List<InstanceDefinition> instanceDefinitions = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions(); assertEquals(2, instanceDefinitions.size()); assertEquals(testPassword1, instanceDefinitions.get(0).getTrustStorePassword()); assertEquals(testPassword2, instanceDefinitions.get(1).getTrustStorePassword()); } @Test public void testNifiDnPrefix() throws CommandLineParseException { String testPrefix = "O=apache, CN="; tlsToolkitStandaloneCommandLine.parse("-n", "nifi", "--nifiDnPrefix", testPrefix); StandaloneConfig config = tlsToolkitStandaloneCommandLine.createConfig(); assertEquals(testPrefix, config.getDnPrefix()); } @Test public void testNifiDnSuffix() throws CommandLineParseException { String testSuffix = ", O=apache, OU=nifi"; tlsToolkitStandaloneCommandLine.parse("-n", "nifi", "--nifiDnSuffix", testSuffix); StandaloneConfig config = tlsToolkitStandaloneCommandLine.createConfig(); assertEquals(testSuffix, config.getDnSuffix()); } @Test public void testClientDnDefault() throws CommandLineParseException { tlsToolkitStandaloneCommandLine.parse(); assertEquals(Collections.emptyList(), tlsToolkitStandaloneCommandLine.createConfig().getClientDns()); } @Test public void testClientDnSingle() throws CommandLineParseException { String testCn = "OU=NIFI,CN=testuser"; tlsToolkitStandaloneCommandLine.parse("-C", testCn); List<String> clientDns = tlsToolkitStandaloneCommandLine.createConfig().getClientDns(); assertEquals(1, clientDns.size()); assertEquals(testCn, clientDns.get(0)); } @Test public void testClientDnMulti() throws CommandLineParseException { String testCn = "OU=NIFI,CN=testuser"; String testCn2 = "OU=NIFI,CN=testuser2"; tlsToolkitStandaloneCommandLine.parse("-C", testCn, "-C", testCn2); StandaloneConfig standaloneConfig = tlsToolkitStandaloneCommandLine.createConfig(); List<String> clientDns = standaloneConfig.getClientDns(); assertEquals(2, clientDns.size()); assertEquals(testCn, clientDns.get(0)); assertEquals(testCn2, clientDns.get(1)); assertEquals(2, standaloneConfig.getClientPasswords().size()); } @Test public void testClientPasswordMulti() throws CommandLineParseException { String testCn = "OU=NIFI,CN=testuser"; String testCn2 = "OU=NIFI,CN=testuser2"; String testPass1 = "testPass1"; String testPass2 = "testPass2"; tlsToolkitStandaloneCommandLine.parse("-C", testCn, "-C", testCn2, "-B", testPass1, "-B", testPass2); StandaloneConfig standaloneConfig = tlsToolkitStandaloneCommandLine.createConfig(); List<String> clientDns = standaloneConfig.getClientDns(); assertEquals(2, clientDns.size()); assertEquals(testCn, clientDns.get(0)); assertEquals(testCn2, clientDns.get(1)); List<String> clientPasswords = standaloneConfig.getClientPasswords(); assertEquals(2, clientPasswords.size()); assertEquals(testPass1, clientPasswords.get(0)); assertEquals(testPass2, clientPasswords.get(1)); } @Test public void testNoGlobalOrder() throws CommandLineParseException { String hostname1 = "other0[4-6]"; String hostname2 = "nifi3(2)"; tlsToolkitStandaloneCommandLine.parse("-n", hostname1, "-n", hostname2); Map<InstanceIdentifier, InstanceDefinition> definitionMap = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions().stream() .collect(Collectors.toMap(InstanceDefinition::getInstanceIdentifier, Function.identity())); assertEquals(5, definitionMap.size()); InstanceDefinition nifi3_1 = definitionMap.get(new InstanceIdentifier("nifi3", 1)); assertNotNull(nifi3_1); assertEquals(1, nifi3_1.getInstanceIdentifier().getNumber()); assertEquals(1, nifi3_1.getNumber()); InstanceDefinition nifi3_2 = definitionMap.get(new InstanceIdentifier("nifi3", 2)); assertNotNull(nifi3_2); assertEquals(2, nifi3_2.getInstanceIdentifier().getNumber()); assertEquals(2, nifi3_2.getNumber()); InstanceDefinition other04 = definitionMap.get(new InstanceIdentifier("other04", 1)); assertNotNull(other04); assertEquals(1, other04.getInstanceIdentifier().getNumber()); assertEquals(1, other04.getNumber()); InstanceDefinition other05 = definitionMap.get(new InstanceIdentifier("other05", 1)); assertNotNull(other05); assertEquals(1, other05.getInstanceIdentifier().getNumber()); assertEquals(1, other05.getNumber()); InstanceDefinition other06 = definitionMap.get(new InstanceIdentifier("other06", 1)); assertNotNull(other06); assertEquals(1, other06.getInstanceIdentifier().getNumber()); assertEquals(1, other06.getNumber()); } @Test public void testGlobalOrder() throws CommandLineParseException { String hostname1 = "other0[4-6]"; String hostname2 = "nifi3(2)"; String globalOrder1 = "nifi[1-5](2),other[01-4]"; String globalOrder2 = "other[05-10]"; tlsToolkitStandaloneCommandLine.parse("-n", hostname1, "-n", hostname2, "-G", globalOrder1, "-G", globalOrder2); Map<InstanceIdentifier, InstanceDefinition> definitionMap = tlsToolkitStandaloneCommandLine.createConfig().getInstanceDefinitions().stream() .collect(Collectors.toMap(InstanceDefinition::getInstanceIdentifier, Function.identity())); assertEquals(5, definitionMap.size()); InstanceDefinition nifi3_1 = definitionMap.get(new InstanceIdentifier("nifi3", 1)); assertNotNull(nifi3_1); assertEquals(1, nifi3_1.getInstanceIdentifier().getNumber()); assertEquals(5, nifi3_1.getNumber()); InstanceDefinition nifi3_2 = definitionMap.get(new InstanceIdentifier("nifi3", 2)); assertNotNull(nifi3_2); assertEquals(2, nifi3_2.getInstanceIdentifier().getNumber()); assertEquals(6, nifi3_2.getNumber()); InstanceDefinition other04 = definitionMap.get(new InstanceIdentifier("other04", 1)); assertNotNull(other04); assertEquals(1, other04.getInstanceIdentifier().getNumber()); assertEquals(14, other04.getNumber()); InstanceDefinition other05 = definitionMap.get(new InstanceIdentifier("other05", 1)); assertNotNull(other05); assertEquals(1, other05.getInstanceIdentifier().getNumber()); assertEquals(15, other05.getNumber()); InstanceDefinition other06 = definitionMap.get(new InstanceIdentifier("other06", 1)); assertNotNull(other06); assertEquals(1, other06.getInstanceIdentifier().getNumber()); assertEquals(16, other06.getNumber()); } @Test(expected = IllegalArgumentException.class) public void testBadGlobalOrder() throws CommandLineParseException { tlsToolkitStandaloneCommandLine.parse("-n", "notInGlobalOrder", "-G", "nifi[1-3]"); } @Test public void testDefaultOutputPathRoot() { Path root = Paths.get(".").toAbsolutePath().getRoot().resolve("."); String calculateDefaultOutputDirectory = TlsToolkitStandaloneCommandLine.calculateDefaultOutputDirectory(root); assertEquals(root.toAbsolutePath().getRoot().toString(), calculateDefaultOutputDirectory); } @Test public void testDefaultOutputPath() { Path path = Paths.get("."); String calculateDefaultOutputDirectory = TlsToolkitStandaloneCommandLine.calculateDefaultOutputDirectory(path); assertEquals("../" + path.toAbsolutePath().normalize().getFileName().toString(), calculateDefaultOutputDirectory); } private Properties getProperties() throws IOException { NiFiPropertiesWriter niFiPropertiesWriter = tlsToolkitStandaloneCommandLine.createConfig().getNiFiPropertiesWriterFactory().create(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); niFiPropertiesWriter.writeNiFiProperties(byteArrayOutputStream); Properties properties = new Properties(); properties.load(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); return properties; } }