Resolve paths from the current working directory instead of the config directory (elastic/x-pack-elasticsearch#637)

This commit changes the resolution of the output and input files so that relative paths will be resolved from the
current working directory instead of the x-pack config directory.

relates elastic/x-pack-elasticsearch#621

Original commit: elastic/x-pack-elasticsearch@bbfd83c2d5
This commit is contained in:
Jay Modi 2017-04-12 10:18:56 -04:00 committed by GitHub
parent 253340a597
commit 666e87c29b
2 changed files with 33 additions and 26 deletions

View File

@ -19,6 +19,8 @@ import org.elasticsearch.cli.EnvironmentAwareCommand;
import org.elasticsearch.cli.Terminal;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
@ -27,7 +29,6 @@ import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.XPackPlugin;
import javax.security.auth.x500.X500Principal;
import java.io.IOException;
@ -138,11 +139,11 @@ public class CertificateTool extends EnvironmentAwareCommand {
protected void execute(Terminal terminal, OptionSet options, Environment env) throws Exception {
final boolean csrOnly = options.has(csrSpec);
printIntro(terminal, csrOnly);
final Path outputFile = getOutputFile(terminal, outputPathSpec.value(options), env, csrOnly ? DEFAULT_CSR_FILE : DEFAULT_CERT_FILE);
final Path outputFile = getOutputFile(terminal, outputPathSpec.value(options), csrOnly ? DEFAULT_CSR_FILE : DEFAULT_CERT_FILE);
final String inputFile = inputFileSpec.value(options);
final int keysize = options.has(keysizeSpec) ? keysizeSpec.value(options) : DEFAULT_KEY_SIZE;
if (csrOnly) {
Collection<CertificateInformation> certificateInformations = getCertificateInformationList(terminal, inputFile, env);
Collection<CertificateInformation> certificateInformations = getCertificateInformationList(terminal, inputFile);
generateAndWriteCsrs(outputFile, certificateInformations, keysize);
} else {
final String dn = options.has(caDnSpec) ? caDnSpec.value(options) : AUTO_GEN_CA_DN;
@ -151,7 +152,7 @@ public class CertificateTool extends EnvironmentAwareCommand {
final int days = options.hasArgument(daysSpec) ? daysSpec.value(options) : DEFAULT_DAYS;
CAInfo caInfo = getCAInfo(terminal, dn, caCertPathSpec.value(options), caKeyPathSpec.value(options), keyPass, prompt, env,
keysize, days);
Collection<CertificateInformation> certificateInformations = getCertificateInformationList(terminal, inputFile, env);
Collection<CertificateInformation> certificateInformations = getCertificateInformationList(terminal, inputFile);
generateAndWriteSignedCertificates(outputFile, certificateInformations, caInfo, keysize, days);
}
printConclusion(terminal, csrOnly, outputFile);
@ -171,35 +172,38 @@ public class CertificateTool extends EnvironmentAwareCommand {
*
* @param terminal terminal to communicate with a user
* @param outputPath user specified output file, may be {@code null}
* @param env the environment for this tool to resolve files with
* @return a {@link Path} to the output file
*/
static Path getOutputFile(Terminal terminal, String outputPath, Environment env, String defaultFilename) throws IOException {
static Path getOutputFile(Terminal terminal, String outputPath, String defaultFilename) throws IOException {
Path file;
if (outputPath != null) {
file = XPackPlugin.resolveConfigFile(env, Strings.cleanPath(outputPath));
file = resolvePath(outputPath);
} else {
file = XPackPlugin.resolveConfigFile(env, defaultFilename);
file = resolvePath(defaultFilename);
String input = terminal.readText("Please enter the desired output file [" + file + "]: ");
if (input.isEmpty() == false) {
file = XPackPlugin.resolveConfigFile(env, Strings.cleanPath(input));
file = resolvePath(input);
}
}
return file;
}
@SuppressForbidden(reason = "resolve paths against CWD for a CLI tool")
private static Path resolvePath(String pathStr) {
return PathUtils.get(Strings.cleanPath(pathStr)).toAbsolutePath();
}
/**
* This method handles the collection of information about each instance that is necessary to generate a certificate. The user may
* be prompted or the information can be gathered from a file
* @param terminal the terminal to use for user interaction
* @param inputFile an optional file that will be used to load the instance information
* @param env the environment for this tool to resolve files with
* @return a {@link Collection} of {@link CertificateInformation} that represents each instance
*/
static Collection<CertificateInformation> getCertificateInformationList(Terminal terminal, String inputFile, Environment env)
static Collection<CertificateInformation> getCertificateInformationList(Terminal terminal, String inputFile)
throws Exception {
if (inputFile != null) {
return parseFile(XPackPlugin.resolveConfigFile(env, inputFile));
return parseFile(resolvePath(inputFile));
}
Map<String, CertificateInformation> map = new HashMap<>();
boolean done = false;
@ -307,13 +311,14 @@ public class CertificateTool extends EnvironmentAwareCommand {
Environment env, int keysize, int days) throws Exception {
if (caCertPath != null) {
assert caKeyPath != null;
Certificate[] certificates = CertUtils.readCertificates(Collections.singletonList(caCertPath), env);
final String resolvedCaCertPath = resolvePath(caCertPath).toString();
Certificate[] certificates = CertUtils.readCertificates(Collections.singletonList(resolvedCaCertPath), env);
if (certificates.length != 1) {
throw new IllegalArgumentException("expected a single certificate in file [" + caCertPath + "] but found [" +
certificates.length + "]");
}
Certificate caCert = certificates[0];
PrivateKey privateKey = readPrivateKey(caKeyPath, keyPass, terminal, env, prompt);
PrivateKey privateKey = readPrivateKey(caKeyPath, keyPass, terminal, prompt);
return new CAInfo((X509Certificate) caCert, privateKey);
}
@ -504,14 +509,13 @@ public class CertificateTool extends EnvironmentAwareCommand {
* @param path the path to the private key
* @param password the password provided by the user or {@code null}
* @param terminal the terminal to use for user interaction
* @param env the environment to resolve files from
* @param prompt whether to prompt the user or not
* @return the {@link PrivateKey} that was read from the file
*/
private static PrivateKey readPrivateKey(String path, char[] password, Terminal terminal, Environment env, boolean prompt)
private static PrivateKey readPrivateKey(String path, char[] password, Terminal terminal, boolean prompt)
throws Exception {
AtomicReference<char[]> passwordReference = new AtomicReference<>(password);
try (Reader reader = Files.newBufferedReader(XPackPlugin.resolveConfigFile(env, path), StandardCharsets.UTF_8)) {
try (Reader reader = Files.newBufferedReader(resolvePath(path), StandardCharsets.UTF_8)) {
return CertUtils.readPrivateKey(reader, () -> {
if (password != null || prompt == false) {
return password;

View File

@ -22,11 +22,12 @@ import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.elasticsearch.cli.MockTerminal;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.ssl.CertificateTool.CAInfo;
import org.elasticsearch.xpack.ssl.CertificateTool.CertificateInformation;
import org.elasticsearch.xpack.ssl.CertificateTool.Name;
@ -63,7 +64,6 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.instanceOf;
/**
@ -89,13 +89,12 @@ public class CertificateToolTests extends ESTestCase {
}
public void testOutputDirectory() throws Exception {
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
Path outputDir = createTempDir();
Path outputFile = outputDir.resolve("certs.zip");
MockTerminal terminal = new MockTerminal();
// test with a user provided dir
Path resolvedOutputFile = CertificateTool.getOutputFile(terminal, outputFile.toString(), env, null);
Path resolvedOutputFile = CertificateTool.getOutputFile(terminal, outputFile.toString(), null);
assertEquals(outputFile, resolvedOutputFile);
assertTrue(terminal.getOutput().isEmpty());
@ -103,15 +102,15 @@ public class CertificateToolTests extends ESTestCase {
Path userPromptedOutputFile = outputDir.resolve("csr");
assertFalse(Files.exists(userPromptedOutputFile));
terminal.addTextInput(userPromptedOutputFile.toString());
resolvedOutputFile = CertificateTool.getOutputFile(terminal, null, env, "out.zip");
resolvedOutputFile = CertificateTool.getOutputFile(terminal, null, "out.zip");
assertEquals(userPromptedOutputFile, resolvedOutputFile);
assertTrue(terminal.getOutput().isEmpty());
// test with empty user input
String defaultFilename = randomAlphaOfLengthBetween(1, 10);
Path expectedDefaultPath = XPackPlugin.resolveConfigFile(env, defaultFilename);
Path expectedDefaultPath = resolvePath(defaultFilename);
terminal.addTextInput("");
resolvedOutputFile = CertificateTool.getOutputFile(terminal, null, env, defaultFilename);
resolvedOutputFile = CertificateTool.getOutputFile(terminal, null, defaultFilename);
assertEquals(expectedDefaultPath, resolvedOutputFile);
assertTrue(terminal.getOutput().isEmpty());
}
@ -150,8 +149,7 @@ public class CertificateToolTests extends ESTestCase {
}
}
Collection<CertificateInformation> certInfos = CertificateTool.getCertificateInformationList(terminal, null,
new Environment(Settings.builder().put("path.home", createTempDir()).build()));
Collection<CertificateInformation> certInfos = CertificateTool.getCertificateInformationList(terminal, null);
logger.info("certificate tool output:\n{}", terminal.getOutput());
assertEquals(numberOfInstances, certInfos.size());
for (CertificateInformation certInfo : certInfos) {
@ -487,4 +485,9 @@ public class CertificateToolTests extends ESTestCase {
return Files.write(path, instances, StandardCharsets.UTF_8);
}
@SuppressForbidden(reason = "resolve paths against CWD for a CLI tool")
private static Path resolvePath(String path) {
return PathUtils.get(path).toAbsolutePath();
}
}