Refactors and tests in java-spiffe-helper.
Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
This commit is contained in:
parent
0c542c198c
commit
e81a936a96
|
|
@ -0,0 +1,96 @@
|
||||||
|
package io.spiffe.helper.cli;
|
||||||
|
|
||||||
|
import io.spiffe.helper.exception.RunnerException;
|
||||||
|
import io.spiffe.helper.keystore.KeyStoreHelper.KeyStoreOptions;
|
||||||
|
import io.spiffe.helper.keystore.KeyStoreType;
|
||||||
|
import lombok.val;
|
||||||
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
|
import org.apache.commons.cli.DefaultParser;
|
||||||
|
import org.apache.commons.cli.Option;
|
||||||
|
import org.apache.commons.cli.Options;
|
||||||
|
import org.apache.commons.cli.ParseException;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
|
||||||
|
static final Option CONFIG_FILE_OPTION =
|
||||||
|
Option.builder("c")
|
||||||
|
.longOpt("config")
|
||||||
|
.hasArg(true)
|
||||||
|
.required(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private Config() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static Properties parseConfigFileProperties(final Path configFilePath) throws RunnerException {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
try (InputStream in = Files.newInputStream(configFilePath)) {
|
||||||
|
properties.load(in);
|
||||||
|
} catch (IOException e) {
|
||||||
|
val error = String.format("Cannot open config file: %s", configFilePath);
|
||||||
|
throw new RunnerException(error, e);
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getCliConfigOption(final String... args) throws RunnerException {
|
||||||
|
final Options cliOptions = new Options();
|
||||||
|
cliOptions.addOption(CONFIG_FILE_OPTION);
|
||||||
|
CommandLineParser parser = new DefaultParser();
|
||||||
|
try {
|
||||||
|
val cmd = parser.parse(cliOptions, args);
|
||||||
|
return cmd.getOptionValue("config");
|
||||||
|
} catch (ParseException e) {
|
||||||
|
val error = String.format("%s. Use -c, --config <arg>", e.getMessage());
|
||||||
|
throw new RunnerException(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static KeyStoreOptions createKeyStoreOptions(final Properties properties) {
|
||||||
|
val keyStorePath = getProperty(properties, "keyStorePath");
|
||||||
|
val keyStorePass = getProperty(properties, "keyStorePass");
|
||||||
|
val keyPass = getProperty(properties, "keyPass");
|
||||||
|
val trustStorePath = getProperty(properties, "trustStorePath");
|
||||||
|
val trustStorePass = getProperty(properties, "trustStorePass");
|
||||||
|
|
||||||
|
val keyAlias = properties.getProperty("keyAlias", null);
|
||||||
|
val spiffeSocketPath = properties.getProperty("spiffeSocketPath", null);
|
||||||
|
val keyStoreTypeProp = properties.getProperty("keyStoreType", null);
|
||||||
|
|
||||||
|
KeyStoreType keyStoreType;
|
||||||
|
if (StringUtils.isNotBlank(keyStoreTypeProp)) {
|
||||||
|
keyStoreType = KeyStoreType.parse(keyStoreTypeProp);
|
||||||
|
} else {
|
||||||
|
keyStoreType = KeyStoreType.getDefaultType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return KeyStoreOptions.builder()
|
||||||
|
.keyStorePath(Paths.get(keyStorePath))
|
||||||
|
.keyStorePass(keyStorePass)
|
||||||
|
.keyPass(keyPass)
|
||||||
|
.trustStorePath(Paths.get(trustStorePath))
|
||||||
|
.trustStorePass(trustStorePass)
|
||||||
|
.keyAlias(keyAlias)
|
||||||
|
.spiffeSocketPath(spiffeSocketPath)
|
||||||
|
.keyStoreType(keyStoreType)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getProperty(final Properties properties, final String key) {
|
||||||
|
final String value = properties.getProperty(key);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
throw new InvalidParameterException(String.format("Missing value for config property: %s", key));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,23 +4,12 @@ import io.spiffe.exception.SocketEndpointAddressException;
|
||||||
import io.spiffe.helper.exception.KeyStoreHelperException;
|
import io.spiffe.helper.exception.KeyStoreHelperException;
|
||||||
import io.spiffe.helper.exception.RunnerException;
|
import io.spiffe.helper.exception.RunnerException;
|
||||||
import io.spiffe.helper.keystore.KeyStoreHelper;
|
import io.spiffe.helper.keystore.KeyStoreHelper;
|
||||||
import io.spiffe.helper.keystore.KeyStoreType;
|
|
||||||
import lombok.extern.java.Log;
|
import lombok.extern.java.Log;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.DefaultParser;
|
|
||||||
import org.apache.commons.cli.Option;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Properties;
|
import java.security.InvalidParameterException;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point of the CLI to run the KeyStoreHelper.
|
* Entry point of the CLI to run the KeyStoreHelper.
|
||||||
|
|
@ -37,102 +26,19 @@ public class Runner {
|
||||||
* In the args needs to be passed the config file option as: "-c" and "path_to_config_file"
|
* In the args needs to be passed the config file option as: "-c" and "path_to_config_file"
|
||||||
*
|
*
|
||||||
* @param args contains the option with the config file path
|
* @param args contains the option with the config file path
|
||||||
|
* @throws RunnerException is there is an error configuring or creating the KeyStoreHelper.
|
||||||
*/
|
*/
|
||||||
public static void main(final String ...args) throws RunnerException {
|
public static void main(final String ...args) throws RunnerException {
|
||||||
String configFilePath = null;
|
|
||||||
try {
|
try {
|
||||||
configFilePath = getCliConfigOption(args);
|
val configFilePath = Config.getCliConfigOption(args);
|
||||||
val parameters = parseConfigFile(Paths.get(configFilePath));
|
val properties = Config.parseConfigFileProperties(Paths.get(configFilePath));
|
||||||
val options = toKeyStoreOptions(parameters);
|
val options = Config.createKeyStoreOptions(properties);
|
||||||
try (val keyStoreHelper = KeyStoreHelper.create(options)) {
|
try (val keyStoreHelper = KeyStoreHelper.create(options)) {
|
||||||
keyStoreHelper.run(true);
|
keyStoreHelper.run(true);
|
||||||
}
|
}
|
||||||
} catch (SocketEndpointAddressException | KeyStoreHelperException | RunnerException | IllegalArgumentException e) {
|
} catch (SocketEndpointAddressException | KeyStoreHelperException | RunnerException | InvalidParameterException | KeyStoreException e) {
|
||||||
log.severe(e.getMessage());
|
log.severe(e.getMessage());
|
||||||
throw new RunnerException(e);
|
throw new RunnerException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Properties parseConfigFile(final Path configFilePath) throws RunnerException {
|
|
||||||
Properties prop = new Properties();
|
|
||||||
try (InputStream in = Files.newInputStream(configFilePath)) {
|
|
||||||
prop.load(in);
|
|
||||||
} catch (IOException e) {
|
|
||||||
val error = String.format("Cannot open config file: %s %n %s", configFilePath, e.getMessage());
|
|
||||||
throw new RunnerException(error);
|
|
||||||
}
|
|
||||||
return prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getCliConfigOption(final String ...args) throws RunnerException {
|
|
||||||
final Options cliOptions = new Options();
|
|
||||||
final Option confOption = new Option("c", "config", true, "config file");
|
|
||||||
confOption.setRequired(true);
|
|
||||||
cliOptions.addOption(confOption);
|
|
||||||
CommandLineParser parser = new DefaultParser();
|
|
||||||
CommandLine cmd = null;
|
|
||||||
try {
|
|
||||||
cmd = parser.parse(cliOptions, args);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
val error = String.format( "%s. Use -c, --config <arg>", e.getMessage());
|
|
||||||
throw new RunnerException(error);
|
|
||||||
}
|
|
||||||
return cmd.getOptionValue("config");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static KeyStoreHelper.KeyStoreOptions toKeyStoreOptions(final Properties properties) {
|
|
||||||
|
|
||||||
val keyStorePath = getString(properties, "keyStorePath");
|
|
||||||
if (StringUtils.isBlank(keyStorePath)) {
|
|
||||||
throw new IllegalArgumentException("keyStorePath config is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
val keyStorePass = getString(properties, "keyStorePass");
|
|
||||||
if (StringUtils.isBlank(keyStorePass)) {
|
|
||||||
throw new IllegalArgumentException("keyStorePass config is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
val keyPass = getString(properties, "keyPass");
|
|
||||||
if (StringUtils.isBlank(keyPass)) {
|
|
||||||
throw new IllegalArgumentException("keyPass config is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
val trustStorePath = getString(properties, "trustStorePath");
|
|
||||||
if (StringUtils.isBlank(trustStorePath)) {
|
|
||||||
throw new IllegalArgumentException("trustStorePath config is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
val trustStorePass = getString(properties, "trustStorePass");
|
|
||||||
if (StringUtils.isBlank(trustStorePass)) {
|
|
||||||
throw new IllegalArgumentException("trustStorePass config is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
val keyAlias = getString(properties, "keyAlias");
|
|
||||||
val spiffeSocketPath = getString(properties, "spiffeSocketPath");
|
|
||||||
|
|
||||||
KeyStoreType keyStoreType = null;
|
|
||||||
val keyStoreTypeProp = properties.get("keyStoreType");
|
|
||||||
if (keyStoreTypeProp != null) {
|
|
||||||
keyStoreType = KeyStoreType.parse(keyStoreTypeProp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return KeyStoreHelper.KeyStoreOptions.builder()
|
|
||||||
.keyStorePath(Paths.get(keyStorePath))
|
|
||||||
.keyStorePass(keyStorePass)
|
|
||||||
.keyPass(keyPass)
|
|
||||||
.trustStorePath(Paths.get(trustStorePath))
|
|
||||||
.trustStorePass(trustStorePass)
|
|
||||||
.keyAlias(keyAlias)
|
|
||||||
.spiffeSocketPath(spiffeSocketPath)
|
|
||||||
.keyStoreType(keyStoreType)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getString(final Properties properties, final String propName) {
|
|
||||||
val property = properties.getProperty(propName);
|
|
||||||
if (property == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return property;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,8 @@ public class RunnerException extends Exception {
|
||||||
public RunnerException(Throwable cause) {
|
public RunnerException(Throwable cause) {
|
||||||
super(cause);
|
super(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RunnerException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ class KeyStore {
|
||||||
}
|
}
|
||||||
return keyStore;
|
return keyStore;
|
||||||
} catch (IOException | NoSuchAlgorithmException | CertificateException e) {
|
} catch (IOException | NoSuchAlgorithmException | CertificateException e) {
|
||||||
throw new KeyStoreException(e);
|
throw new KeyStoreException("KeyStore cannot be created", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,9 @@ public class KeyStoreHelper implements Closeable {
|
||||||
* @return an instance of a KeyStoreHelper
|
* @return an instance of a KeyStoreHelper
|
||||||
* @throws SocketEndpointAddressException if the socket endpoint address is not valid
|
* @throws SocketEndpointAddressException if the socket endpoint address is not valid
|
||||||
* @throws KeyStoreHelperException if the KeyStoreHelper cannot be created
|
* @throws KeyStoreHelperException if the KeyStoreHelper cannot be created
|
||||||
|
* @throws KeyStoreException if the underlying java KeyStore and TrustStore cannot be created
|
||||||
*/
|
*/
|
||||||
public static KeyStoreHelper create(@NonNull final KeyStoreOptions options) throws SocketEndpointAddressException, KeyStoreHelperException {
|
public static KeyStoreHelper create(@NonNull final KeyStoreOptions options) throws SocketEndpointAddressException, KeyStoreHelperException, KeyStoreException {
|
||||||
|
|
||||||
if (options.keyStorePath.equals(options.trustStorePath)) {
|
if (options.keyStorePath.equals(options.trustStorePath)) {
|
||||||
throw new KeyStoreHelperException("KeyStore and TrustStore should use different files");
|
throw new KeyStoreHelperException("KeyStore and TrustStore should use different files");
|
||||||
|
|
@ -142,16 +143,12 @@ public class KeyStoreHelper implements Closeable {
|
||||||
this.workloadApiClient = workloadApiClient;
|
this.workloadApiClient = workloadApiClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KeyStore createKeyStore(KeyStoreOptions options, Path keyStorePath, String keyStorePass) throws KeyStoreHelperException {
|
private static KeyStore createKeyStore(KeyStoreOptions options, Path keyStorePath, String keyStorePass) throws KeyStoreException {
|
||||||
try {
|
return KeyStore.builder()
|
||||||
return KeyStore.builder()
|
.keyStoreFilePath(keyStorePath)
|
||||||
.keyStoreFilePath(keyStorePath)
|
.keyStoreType(options.keyStoreType)
|
||||||
.keyStoreType(options.keyStoreType)
|
.keyStorePassword(keyStorePass)
|
||||||
.keyStorePassword(keyStorePass)
|
.build();
|
||||||
.build();
|
|
||||||
} catch (KeyStoreException e) {
|
|
||||||
throw new KeyStoreHelperException("Error creating KeyStore/TrustStore", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WorkloadApiClient createNewClient(final String spiffeSocketPath) throws SocketEndpointAddressException {
|
private static WorkloadApiClient createNewClient(final String spiffeSocketPath) throws SocketEndpointAddressException {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
package io.spiffe.helper.cli;
|
||||||
|
|
||||||
|
import io.spiffe.helper.exception.RunnerException;
|
||||||
|
import io.spiffe.helper.keystore.KeyStoreHelper;
|
||||||
|
import io.spiffe.helper.keystore.KeyStoreType;
|
||||||
|
import lombok.val;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static io.spiffe.helper.utils.TestUtils.toUri;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
class ConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseConfigFileProperties() throws URISyntaxException {
|
||||||
|
val path = Paths.get(toUri("testdata/cli/correct.conf"));
|
||||||
|
|
||||||
|
Properties properties = null;
|
||||||
|
try {
|
||||||
|
properties = Config.parseConfigFileProperties(path);
|
||||||
|
} catch (RunnerException e) {
|
||||||
|
fail(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("keystore123.p12", properties.getProperty("keyStorePath"));
|
||||||
|
assertEquals("example123", properties.getProperty("keyStorePass"));
|
||||||
|
assertEquals("pass123", properties.getProperty("keyPass"));
|
||||||
|
assertEquals("truststore123.p12", properties.getProperty("trustStorePath"));
|
||||||
|
assertEquals("otherpass123", properties.getProperty("trustStorePass"));
|
||||||
|
assertEquals("jks", properties.getProperty("keyStoreType"));
|
||||||
|
assertEquals("other_alias", properties.getProperty("keyAlias"));
|
||||||
|
assertEquals("unix:/tmp/test", properties.getProperty("spiffeSocketPath"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parseConfigFile_doesNotExist() {
|
||||||
|
val randomFileName = RandomStringUtils.randomAlphabetic(10);
|
||||||
|
val path = Paths.get(randomFileName);
|
||||||
|
try {
|
||||||
|
Config.parseConfigFileProperties(path);
|
||||||
|
fail();
|
||||||
|
} catch (RunnerException e) {
|
||||||
|
assertEquals("Cannot open config file: " + randomFileName, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getCliConfigOption_validOption() {
|
||||||
|
try {
|
||||||
|
String option = Config.getCliConfigOption("-c", "test");
|
||||||
|
assertEquals("test", option);
|
||||||
|
} catch (RunnerException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getCliConfigOption_validLongOption() {
|
||||||
|
try {
|
||||||
|
String option = Config.getCliConfigOption("--config", "example");
|
||||||
|
assertEquals("example", option);
|
||||||
|
} catch (RunnerException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getCliConfigOption_unknownOption() {
|
||||||
|
try {
|
||||||
|
String option = Config.getCliConfigOption("-a", "test");
|
||||||
|
} catch (RunnerException e) {
|
||||||
|
assertEquals("Unrecognized option: -a. Use -c, --config <arg>", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetCliConfigOption_unknownLongOption() {
|
||||||
|
try {
|
||||||
|
Config.getCliConfigOption("--unknown", "example");
|
||||||
|
fail("expected parse exception");
|
||||||
|
} catch (RunnerException e) {
|
||||||
|
assertEquals("Unrecognized option: --unknown. Use -c, --config <arg>", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createKeyStoreOptions() throws URISyntaxException {
|
||||||
|
Properties configuration = getValidConfiguration();
|
||||||
|
KeyStoreHelper.KeyStoreOptions keyStoreOptions = Config.createKeyStoreOptions(configuration);
|
||||||
|
|
||||||
|
assertEquals("keystore123.p12", keyStoreOptions.getKeyStorePath().toString());
|
||||||
|
assertEquals("example123", keyStoreOptions.getKeyStorePass());
|
||||||
|
assertEquals("pass123", keyStoreOptions.getKeyPass());
|
||||||
|
assertEquals("truststore123.p12", keyStoreOptions.getTrustStorePath().toString());
|
||||||
|
assertEquals("otherpass123", keyStoreOptions.getTrustStorePass());
|
||||||
|
assertEquals("jks", keyStoreOptions.getKeyStoreType().value());
|
||||||
|
assertEquals("other_alias", keyStoreOptions.getKeyAlias());
|
||||||
|
assertEquals("unix:/tmp/test", keyStoreOptions.getSpiffeSocketPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createKeyStoreOptions_aRequiredProperty_is_missing() throws URISyntaxException {
|
||||||
|
Properties configuration = getValidConfiguration();
|
||||||
|
|
||||||
|
// remove a required config
|
||||||
|
configuration.setProperty("trustStorePass", "");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Config.createKeyStoreOptions(configuration);
|
||||||
|
fail();
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertEquals("Missing value for config property: trustStorePass", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createKeyStoreOptions_keyStoreTypeMissing_useDefault() throws URISyntaxException {
|
||||||
|
Properties configuration = getValidConfiguration();
|
||||||
|
|
||||||
|
configuration.setProperty("keyStoreType", "");
|
||||||
|
|
||||||
|
KeyStoreHelper.KeyStoreOptions keyStoreOptions = Config.createKeyStoreOptions(configuration);
|
||||||
|
assertEquals(KeyStoreType.getDefaultType(), keyStoreOptions.getKeyStoreType());
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties getValidConfiguration() throws URISyntaxException {
|
||||||
|
val path = Paths.get(toUri("testdata/cli/correct.conf"));
|
||||||
|
Properties properties = null;
|
||||||
|
try {
|
||||||
|
return Config.parseConfigFileProperties(path);
|
||||||
|
} catch (RunnerException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
package io.spiffe.helper.cli;
|
package io.spiffe.helper.cli;
|
||||||
|
|
||||||
import io.spiffe.exception.SocketEndpointAddressException;
|
|
||||||
import io.spiffe.helper.exception.RunnerException;
|
import io.spiffe.helper.exception.RunnerException;
|
||||||
|
import lombok.val;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import static io.spiffe.helper.utils.TestUtils.toUri;
|
import static io.spiffe.helper.utils.TestUtils.toUri;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
@ -17,104 +17,73 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
class RunnerTest {
|
class RunnerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test_Main_KeyStorePathIsMissing() throws KeyStoreException, SocketEndpointAddressException, URISyntaxException {
|
void test_Main_KeyStorePathIsMissing() throws URISyntaxException {
|
||||||
final Path path = Paths.get(toUri("testdata/cli/missing-keystorepath.conf"));
|
final Path path = Paths.get(toUri("testdata/cli/missing-keystorepath.conf"));
|
||||||
try {
|
try {
|
||||||
Runner.main("-c", path.toString());
|
Runner.main("-c", path.toString());
|
||||||
fail("expected exception: property is missing");
|
fail("expected exception: property is missing");
|
||||||
} catch (RunnerException e) {
|
} catch (RunnerException e) {
|
||||||
assertEquals("keyStorePath config is missing", e.getCause().getMessage());
|
assertEquals("Missing value for config property: keyStorePath", e.getCause().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test_Main_KeyStorePassIsMissing() throws KeyStoreException, SocketEndpointAddressException, URISyntaxException {
|
void test_Main_KeyStorePassIsMissing() throws URISyntaxException {
|
||||||
final Path path = Paths.get(toUri("testdata/cli/missing-keystorepass.conf"));
|
final Path path = Paths.get(toUri("testdata/cli/missing-keystorepass.conf"));
|
||||||
try {
|
try {
|
||||||
Runner.main("-c", path.toString());
|
Runner.main("-c", path.toString());
|
||||||
fail("expected exception: property is missing");
|
fail("expected exception: property is missing");
|
||||||
} catch (RunnerException e) {
|
} catch (RunnerException e) {
|
||||||
assertEquals("keyStorePass config is missing", e.getCause().getMessage());
|
assertEquals("Missing value for config property: keyStorePass", e.getCause().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test_Main_KeyPassIsMissing() throws KeyStoreException, SocketEndpointAddressException, URISyntaxException {
|
void test_Main_KeyPassIsMissing() throws URISyntaxException {
|
||||||
final Path path = Paths.get(toUri("testdata/cli/missing-keypass.conf"));
|
final Path path = Paths.get(toUri("testdata/cli/missing-keypass.conf"));
|
||||||
try {
|
try {
|
||||||
Runner.main("-c", path.toString());
|
Runner.main("-c", path.toString());
|
||||||
fail("expected exception: property is missing");
|
fail("expected exception: property is missing");
|
||||||
} catch (RunnerException e) {
|
} catch (RunnerException e) {
|
||||||
assertEquals("keyPass config is missing", e.getCause().getMessage());
|
assertEquals("Missing value for config property: keyPass", e.getCause().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test_Main_TrustStorePathIsMissing() throws KeyStoreException, SocketEndpointAddressException, URISyntaxException {
|
void test_Main_TrustStorePathIsMissing() throws URISyntaxException {
|
||||||
final Path path = Paths.get(toUri("testdata/cli/missing-truststorepath.conf"));
|
final Path path = Paths.get(toUri("testdata/cli/missing-truststorepath.conf"));
|
||||||
try {
|
try {
|
||||||
Runner.main("-c", path.toString());
|
Runner.main("-c", path.toString());
|
||||||
fail("expected exception: property is missing");
|
fail("expected exception: property is missing");
|
||||||
} catch (RunnerException e) {
|
} catch (RunnerException e) {
|
||||||
assertEquals("trustStorePath config is missing", e.getCause().getMessage());
|
assertEquals("Missing value for config property: trustStorePath", e.getCause().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test_Main_TrustStorePassIsMissing() throws KeyStoreException, SocketEndpointAddressException, URISyntaxException {
|
void test_Main_TrustStorePassIsMissing() throws URISyntaxException {
|
||||||
final Path path = Paths.get(toUri("testdata/cli/missing-truststorepass.conf"));
|
final Path path = Paths.get(toUri("testdata/cli/missing-truststorepass.conf"));
|
||||||
try {
|
try {
|
||||||
Runner.main("-c", path.toString());
|
Runner.main("-c", path.toString());
|
||||||
fail("expected exception: property is missing");
|
fail("expected exception: property is missing");
|
||||||
} catch (RunnerException e) {
|
} catch (RunnerException e) {
|
||||||
assertEquals("trustStorePass config is missing", e.getCause().getMessage());
|
assertEquals("Missing value for config property: trustStorePass", e.getCause().getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetCliConfigOption_abbreviated() {
|
void test_Main_throwsExceptionIfTheKeystoreCannotBeCreated() throws URISyntaxException, IOException {
|
||||||
String option = null;
|
val file = new File("keystore123.p12");
|
||||||
|
file.createNewFile();
|
||||||
|
|
||||||
|
val configPath = Paths.get(toUri("testdata/cli/correct.conf"));
|
||||||
try {
|
try {
|
||||||
option = Runner.getCliConfigOption("-c", "example");
|
Runner.main("-c", configPath.toString());
|
||||||
} catch (RunnerException e) {
|
} catch (RunnerException e) {
|
||||||
fail(e);
|
assertEquals("KeyStore cannot be created", e.getCause().getMessage());
|
||||||
}
|
} finally {
|
||||||
assertEquals("example", option);
|
file.delete();
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGetCliConfigOption() {
|
|
||||||
String option = null;
|
|
||||||
try {
|
|
||||||
option = Runner.getCliConfigOption("--config", "example");
|
|
||||||
} catch (RunnerException e) {
|
|
||||||
fail(e);
|
|
||||||
}
|
|
||||||
assertEquals("example", option);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGetCliConfigOption_nonExistent() {
|
|
||||||
try {
|
|
||||||
Runner.getCliConfigOption("--unknown", "example");
|
|
||||||
fail("expected parse exception");
|
|
||||||
} catch (RunnerException e) {
|
|
||||||
assertEquals("Unrecognized option: --unknown. Use -c, --config <arg>", e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void test_ParseConfigFile() throws URISyntaxException, RunnerException {
|
|
||||||
final Path path = Paths.get(toUri("testdata/cli/correct.conf"));
|
|
||||||
final Properties properties = Runner.parseConfigFile(path);
|
|
||||||
|
|
||||||
assertEquals("keystore123.p12", properties.getProperty("keyStorePath"));
|
|
||||||
assertEquals("example123", properties.getProperty("keyStorePass"));
|
|
||||||
assertEquals("pass123", properties.getProperty("keyPass"));
|
|
||||||
assertEquals("truststore123.p12", properties.getProperty("trustStorePath"));
|
|
||||||
assertEquals("otherpass123", properties.getProperty("trustStorePass"));
|
|
||||||
assertEquals("jks", properties.getProperty("keyStoreType"));
|
|
||||||
assertEquals("other_alias", properties.getProperty("keyAlias"));
|
|
||||||
assertEquals("unix:/tmp/agent.sock", properties.getProperty("spiffeSocketPath"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -149,6 +149,8 @@ class KeyStoreHelperTest {
|
||||||
fail("expected exception: KeyStore and TrustStore should use different files");
|
fail("expected exception: KeyStore and TrustStore should use different files");
|
||||||
} catch (KeyStoreHelperException e) {
|
} catch (KeyStoreHelperException e) {
|
||||||
assertEquals("KeyStore and TrustStore should use different files", e.getMessage());
|
assertEquals("KeyStore and TrustStore should use different files", e.getMessage());
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
fail(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,6 +183,8 @@ class KeyStoreHelperTest {
|
||||||
} catch (KeyStoreHelperException e) {
|
} catch (KeyStoreHelperException e) {
|
||||||
assertEquals("Error running KeyStoreHelper", e.getMessage());
|
assertEquals("Error running KeyStoreHelper", e.getMessage());
|
||||||
assertEquals("java.nio.file.NoSuchFileException: dummy:/invalid", e.getCause().getCause().getMessage());
|
assertEquals("java.nio.file.NoSuchFileException: dummy:/invalid", e.getCause().getCause().getMessage());
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
fail(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +205,7 @@ class KeyStoreHelperTest {
|
||||||
KeyStoreHelper.create(null);
|
KeyStoreHelper.create(null);
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
assertEquals("options is marked non-null but is null", e.getMessage());
|
assertEquals("options is marked non-null but is null", e.getMessage());
|
||||||
} catch (SocketEndpointAddressException | KeyStoreHelperException e) {
|
} catch (SocketEndpointAddressException | KeyStoreHelperException | KeyStoreException e) {
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -232,6 +236,70 @@ class KeyStoreHelperTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void keyStoreHelperOptions_allNull() {
|
||||||
|
try {
|
||||||
|
KeyStoreHelper.KeyStoreOptions.builder().build();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertEquals("keyStorePath is marked non-null but is null", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void keyStoreHelperOptions_trustStorePathNull() {
|
||||||
|
try {
|
||||||
|
KeyStoreHelper.KeyStoreOptions
|
||||||
|
.builder()
|
||||||
|
.keyStorePath(Paths.get("test"))
|
||||||
|
.build();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertEquals("trustStorePath is marked non-null but is null", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void keyStoreHelperOptions_keyStorePassNull() {
|
||||||
|
try {
|
||||||
|
KeyStoreHelper.KeyStoreOptions
|
||||||
|
.builder()
|
||||||
|
.keyStorePath(Paths.get("test"))
|
||||||
|
.trustStorePath(Paths.get("example"))
|
||||||
|
.build();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertEquals("keyStorePass is marked non-null but is null", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void keyStoreHelperOptions_trustStorePassNull() {
|
||||||
|
try {
|
||||||
|
KeyStoreHelper.KeyStoreOptions
|
||||||
|
.builder()
|
||||||
|
.keyStorePath(Paths.get("test"))
|
||||||
|
.trustStorePath(Paths.get("example"))
|
||||||
|
.keyStorePass("example1")
|
||||||
|
.build();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertEquals("trustStorePass is marked non-null but is null", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void keyStoreHelperOptions_keyPassNull() {
|
||||||
|
try {
|
||||||
|
KeyStoreHelper.KeyStoreOptions
|
||||||
|
.builder()
|
||||||
|
.keyStorePath(Paths.get("test"))
|
||||||
|
.trustStorePath(Paths.get("example"))
|
||||||
|
.keyStorePass("example1")
|
||||||
|
.trustStorePass("example2")
|
||||||
|
.build();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertEquals("keyPass is marked non-null but is null", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private KeyStoreHelper.KeyStoreOptions getKeyStoreValidOptions(WorkloadApiClient workloadApiClient) {
|
private KeyStoreHelper.KeyStoreOptions getKeyStoreValidOptions(WorkloadApiClient workloadApiClient) {
|
||||||
val keyStorefileName = RandomStringUtils.randomAlphabetic(10);
|
val keyStorefileName = RandomStringUtils.randomAlphabetic(10);
|
||||||
keyStoreFilePath = Paths.get(keyStorefileName);
|
keyStoreFilePath = Paths.get(keyStorefileName);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
|
@ -144,26 +145,33 @@ public class KeyStoreTest {
|
||||||
@Test
|
@Test
|
||||||
void testNewKeyStore_nullKeyStorePath_throwsException() throws KeyStoreException {
|
void testNewKeyStore_nullKeyStorePath_throwsException() throws KeyStoreException {
|
||||||
try {
|
try {
|
||||||
KeyStore.builder()
|
KeyStore.builder().build();
|
||||||
.keyStoreFilePath(null)
|
|
||||||
.keyStoreType(KeyStoreType.JKS)
|
|
||||||
.keyStorePassword("keyStorePassword")
|
|
||||||
.build();
|
|
||||||
fail("exception expected");
|
fail("exception expected");
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
assertEquals("keyStoreFilePath is marked non-null but is null", e.getMessage());
|
assertEquals("keyStoreFilePath is marked non-null but is null", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNewKeyStore_nullKeyStoreType_throwsException() throws KeyStoreException {
|
||||||
|
try {
|
||||||
|
KeyStore.builder()
|
||||||
|
.keyStoreFilePath(Paths.get("anypath"))
|
||||||
|
.build();
|
||||||
|
fail("exception expected");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertEquals("keyStoreType is marked non-null but is null", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNewKeyStore_nullKeyStorePassword_throwsException() throws KeyStoreException {
|
void testNewKeyStore_nullKeyStorePassword_throwsException() throws KeyStoreException {
|
||||||
try {
|
try {
|
||||||
KeyStore.builder()
|
KeyStore.builder()
|
||||||
.keyStoreFilePath(Paths.get("anypath"))
|
.keyStoreFilePath(Paths.get("anypath"))
|
||||||
.keyStoreType(KeyStoreType.PKCS12)
|
.keyStoreType(KeyStoreType.PKCS12)
|
||||||
.keyStorePassword(null)
|
|
||||||
.build();
|
.build();
|
||||||
fail("exception expected");
|
fail("exception expected: keyStorePassword cannot be blank");
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
assertEquals("keyStorePassword is marked non-null but is null", e.getMessage());
|
assertEquals("keyStorePassword is marked non-null but is null", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
@ -183,6 +191,23 @@ public class KeyStoreTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testLoadKeyStore_invalidFile() throws IOException {
|
||||||
|
File file = new File("test.txt");
|
||||||
|
file.createNewFile();
|
||||||
|
try {
|
||||||
|
KeyStore.builder()
|
||||||
|
.keyStoreFilePath(file.toPath())
|
||||||
|
.keyStoreType(KeyStoreType.PKCS12)
|
||||||
|
.keyStorePassword("example")
|
||||||
|
.build();
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
assertEquals("KeyStore cannot be created", e.getMessage());
|
||||||
|
} finally {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
void tearDown() {
|
void tearDown() {
|
||||||
deleteFile(keyStoreFilePath);
|
deleteFile(keyStoreFilePath);
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ trustStorePath = truststore123.p12
|
||||||
trustStorePass = otherpass123
|
trustStorePass = otherpass123
|
||||||
keyStoreType = jks
|
keyStoreType = jks
|
||||||
keyAlias = other_alias
|
keyAlias = other_alias
|
||||||
spiffeSocketPath = unix:/tmp/agent.sock
|
spiffeSocketPath = unix:/tmp/test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue