Add --keypass option to CLI
Up to now we only supported the default key pass (the same as the store password). This change adds a new option to "encrypt" and "decrypt" commands. Fixes gh-26
This commit is contained in:
@@ -40,6 +40,8 @@ class BaseEncryptOptionHandler extends OptionHandler {
|
|||||||
|
|
||||||
private OptionSpec<String> passwordOption;
|
private OptionSpec<String> passwordOption;
|
||||||
|
|
||||||
|
private OptionSpec<String> keyPassOption;
|
||||||
|
|
||||||
private Charset charset;
|
private Charset charset;
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -48,16 +50,18 @@ class BaseEncryptOptionHandler extends OptionHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final void options() {
|
protected final void options() {
|
||||||
this.keyOption = option(
|
this.keyOption = option(asList("key", "k"),
|
||||||
asList("key", "k"),
|
|
||||||
"Specify key (symmetric secret, or pem-encoded key). If the value starts with @ it is interpreted as a file location.")
|
"Specify key (symmetric secret, or pem-encoded key). If the value starts with @ it is interpreted as a file location.")
|
||||||
.withRequiredArg();
|
.withRequiredArg();
|
||||||
this.passwordOption = option("password",
|
this.passwordOption = option("password",
|
||||||
"A password for the keyfile (assuming the --key option is a KetStore file).")
|
"A password for the keyfile (assuming the --key option is a KeyStore file).")
|
||||||
.withRequiredArg();
|
.withRequiredArg();
|
||||||
|
this.keyPassOption = option("keypass",
|
||||||
|
"A password for the key, defaults to the same as the store password (assuming the --key option is a KeyStore file).")
|
||||||
|
.withRequiredArg();
|
||||||
this.aliasOption = option("alias",
|
this.aliasOption = option("alias",
|
||||||
"An alias for the the key in a keyfile (assuming the --key option is a KetStore file).")
|
"An alias for the the key in a keyfile (assuming the --key option is a KeyStore file).")
|
||||||
.withRequiredArg();
|
.withRequiredArg();
|
||||||
doOptions();
|
doOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,17 +70,25 @@ class BaseEncryptOptionHandler extends OptionHandler {
|
|||||||
|
|
||||||
protected TextEncryptor createEncryptor(OptionSet options) {
|
protected TextEncryptor createEncryptor(OptionSet options) {
|
||||||
String value = keyOption.value(options);
|
String value = keyOption.value(options);
|
||||||
if (value==null) {
|
if (value == null) {
|
||||||
throw new MissingKeyException();
|
throw new MissingKeyException();
|
||||||
}
|
}
|
||||||
if (options.has(passwordOption)) { // it's a keystore
|
if (options.has(passwordOption)) { // it's a keystore
|
||||||
String password = options.valueOf(passwordOption);
|
String password = options.valueOf(passwordOption);
|
||||||
String alias = options.valueOf(aliasOption);
|
String alias = options.valueOf(aliasOption);
|
||||||
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new FileSystemResource(
|
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
|
||||||
value), password.toCharArray());
|
new FileSystemResource(value), password.toCharArray());
|
||||||
RsaSecretEncryptor encryptor = new RsaSecretEncryptor(
|
if (options.has(keyPassOption)) {
|
||||||
factory.getKeyPair(alias));
|
String keypass = options.valueOf(keyPassOption);
|
||||||
return encryptor;
|
RsaSecretEncryptor encryptor = new RsaSecretEncryptor(
|
||||||
|
factory.getKeyPair(alias, keypass.toCharArray()));
|
||||||
|
return encryptor;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RsaSecretEncryptor encryptor = new RsaSecretEncryptor(
|
||||||
|
factory.getKeyPair(alias));
|
||||||
|
return encryptor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
boolean verbose = Boolean.getBoolean("debug");
|
boolean verbose = Boolean.getBoolean("debug");
|
||||||
if (value.startsWith("@")) {
|
if (value.startsWith("@")) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.nio.charset.Charset;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.boot.cli.command.status.ExitStatus;
|
import org.springframework.boot.cli.command.status.ExitStatus;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
|
||||||
import org.springframework.security.rsa.crypto.RsaSecretEncryptor;
|
import org.springframework.security.rsa.crypto.RsaSecretEncryptor;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
@@ -49,6 +50,19 @@ public class DecryptCommandTests {
|
|||||||
command.run("-k", "@src/test/resources/private.pem", cipher));
|
command.run("-k", "@src/test/resources/private.pem", cipher));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void decryptsFromRsaKeyWithKeyStore() throws Exception {
|
||||||
|
KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
|
||||||
|
new ClassPathResource("keystore.jks"), "letmein".toCharArray());
|
||||||
|
RsaSecretEncryptor encryptor = new RsaSecretEncryptor(
|
||||||
|
factory.getKeyPair("mytestkey", "changeme".toCharArray()));
|
||||||
|
String cipher = encryptor.encrypt("foo");
|
||||||
|
assertEquals(ExitStatus.OK,
|
||||||
|
command.run("-k", "src/test/resources/keystore.jks", "--password",
|
||||||
|
"letmein", "--keypass", "changeme", "--alias", "mytestkey",
|
||||||
|
cipher));
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void failsWithPlainText() throws Exception {
|
public void failsWithPlainText() throws Exception {
|
||||||
assertEquals(ExitStatus.OK, command.run("-k", "deadbeef", "foo"));
|
assertEquals(ExitStatus.OK, command.run("-k", "deadbeef", "foo"));
|
||||||
|
|||||||
BIN
spring-cloud-cli/src/test/resources/keystore.jks
Normal file
BIN
spring-cloud-cli/src/test/resources/keystore.jks
Normal file
Binary file not shown.
Reference in New Issue
Block a user