Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve keygen CLI output, fix security advisories in key vault modules #1464

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import java.time.Duration

plugins {
id "org.owasp.dependencycheck" version "7.0.4.1"
id "org.owasp.dependencycheck" version "7.1.0.1"
id 'jacoco'
id 'com.diffplug.gradle.spotless' version '3.25.0'
id "io.github.gradle-nexus.publish-plugin" version "1.1.0"
Expand Down Expand Up @@ -248,6 +248,9 @@ subprojects {
dependencyCheck {
failBuildOnCVSS = 0
suppressionFile = project.getRootProject().file("cvss-suppressions.xml")
analyzers {
assemblyEnabled = false
}
}

jacoco {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,12 @@ public void testConfigPathStaysNullWithoutSpecifiedPath() {
serverURIOutputMixin.updateConfig(null, config);
assertThat(config.getOutputServerURIPath()).isNull();
}

@Test
public void defaultDoNothing() {
final Config config = new Config();
assertThat(config.getOutputServerURIPath()).isNull();
serverURIOutputMixin.updateConfig(config);
assertThat(config.getOutputServerURIPath()).isNull();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
import com.quorum.tessera.cli.CliException;
import com.quorum.tessera.cli.CliResult;
import com.quorum.tessera.config.*;
import com.quorum.tessera.config.keypairs.ConfigKeyPair;
import com.quorum.tessera.config.keypairs.*;
import com.quorum.tessera.config.util.ConfigFileUpdaterWriter;
import com.quorum.tessera.config.util.PasswordFileUpdaterWriter;
import com.quorum.tessera.key.generation.GeneratedKeyPair;
import com.quorum.tessera.key.generation.KeyGenerator;
import com.quorum.tessera.key.generation.KeyGeneratorFactory;
import com.quorum.tessera.key.generation.KeyVaultOptions;
Expand All @@ -18,6 +19,8 @@
import java.util.concurrent.Callable;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;

@CommandLine.Command(
Expand All @@ -34,6 +37,8 @@
subcommands = {CommandLine.HelpCommand.class})
public class KeyGenCommand implements Callable<CliResult> {

private static final Logger LOGGER = LoggerFactory.getLogger(KeyGenCommand.class);

private final KeyGeneratorFactory keyGeneratorFactory;

private final ConfigFileUpdaterWriter configFileUpdaterWriter;
Expand Down Expand Up @@ -83,6 +88,79 @@ public class KeyGenCommand implements Callable<CliResult> {
this.keyDataMarshaller = Objects.requireNonNull(keyDataMarshaller);
}

static void output(List<GeneratedKeyPair> generatedKeyPairs) {
StringJoiner sj = new StringJoiner("\n");
sj.add(String.format("%d keypair(s) generated:", generatedKeyPairs.size()));

int i = 0;
for (GeneratedKeyPair kp : generatedKeyPairs) {
i++;
if (kp.getConfigKeyPair() instanceof AzureVaultKeyPair) {
AzureVaultKeyPair akp = (AzureVaultKeyPair) kp.getConfigKeyPair();
String type = "azure";
String pubKey = kp.getPublicKey();
String pubId = akp.getPublicKeyId();
String privId = akp.getPrivateKeyId();
String pubVersion = akp.getPublicKeyVersion();
String privVersion = akp.getPrivateKeyVersion();

sj.add(String.format("\t%d: type=%s, pub=%s", i, type, pubKey));
sj.add(String.format("\t\tpub: id=%s, version=%s", pubId, pubVersion));
sj.add(String.format("\t\tprv: id=%s, version=%s", privId, privVersion));
} else if (kp.getConfigKeyPair() instanceof AWSKeyPair) {
AWSKeyPair akp = (AWSKeyPair) kp.getConfigKeyPair();
String type = "aws";
String pubKey = kp.getPublicKey();
String pubId = akp.getPublicKeyId();
String privId = akp.getPrivateKeyId();

sj.add(String.format("\t%d: type=%s, pub=%s", i, type, pubKey));
sj.add(String.format("\t\tpub: id=%s", pubId));
sj.add(String.format("\t\tprv: id=%s", privId));
} else if (kp.getConfigKeyPair() instanceof HashicorpVaultKeyPair) {
HashicorpVaultKeyPair hkp = (HashicorpVaultKeyPair) kp.getConfigKeyPair();
String type = "hashicorp";
String pubKey = kp.getPublicKey();
String name = hkp.getSecretName();
String secretEngine = hkp.getSecretEngineName();
String version = hkp.getSecretVersion().toString();
String pubId = hkp.getPublicKeyId();
String privId = hkp.getPrivateKeyId();

sj.add(String.format("\t%d: type=%s, pub=%s", i, type, pubKey));
sj.add(
String.format(
"\t\tpub: name=%s/%s, id=%s, version=%s", secretEngine, name, pubId, version));
sj.add(
String.format(
"\t\tprv: name=%s/%s, id=%s, version=%s", secretEngine, name, privId, version));
} else if (kp.getConfigKeyPair() instanceof FilesystemKeyPair) {
FilesystemKeyPair fkp = (FilesystemKeyPair) kp.getConfigKeyPair();
String type = "file";
String pubPath = fkp.getPublicKeyPath().toAbsolutePath().toString();
String privPath = fkp.getPrivateKeyPath().toAbsolutePath().toString();
String pubKey = kp.getPublicKey();

sj.add(String.format("\t%d: type=%s, pub=%s", i, type, pubKey));
sj.add(String.format("\t\tpub: path=%s", pubPath));
sj.add(String.format("\t\tprv: path=%s", privPath));
} else {
sj.add(
String.format("\t%d: type=unknown, pub=%s", i, kp.getConfigKeyPair().getPublicKey()));
}
}
System.out.println(sj);
}

static void prepareConfigForNewKeys(Config config) {
if (Objects.isNull(config.getKeys())) {
config.setKeys(new KeyConfiguration());
}
if (Objects.isNull(config.getKeys().getKeyData())) {
config.getKeys().setKeyData(new ArrayList<>());
}
}

@Override
public CliResult call() throws IOException {
if (Objects.nonNull(fileUpdateOptions) && Objects.isNull(fileUpdateOptions.getConfig())) {
Expand Down Expand Up @@ -118,12 +196,10 @@ public CliResult call() throws IOException {
.flatMap(c -> c.getKeyVaultConfig(keyVaultConfigOptions.getVaultType()))
.orElse(null);
} else {

final KeyVaultHandler keyVaultHandler = new DispatchingKeyVaultHandler();
keyVaultConfig = keyVaultHandler.handle(keyVaultConfigOptions);

if (keyVaultConfig.getKeyVaultType() == KeyVaultType.HASHICORP) {

if (Objects.isNull(keyOut)) {
throw new CliException(
"At least one -filename must be provided when saving generated keys in a Hashicorp Vault");
Expand All @@ -145,24 +221,30 @@ public CliResult call() throws IOException {
.map(List::copyOf)
.orElseGet(() -> List.of(""));

final List<ConfigKeyPair> newConfigKeyPairs =
final List<GeneratedKeyPair> generatedKeyPairs =
newKeyNames.stream()
.map(name -> keyGenerator.generate(name, argonOptions, keyVaultOptions))
.collect(Collectors.toList());

output(generatedKeyPairs);

final List<char[]> newPasswords =
newConfigKeyPairs.stream()
generatedKeyPairs.stream()
.filter(Objects::nonNull)
.map(GeneratedKeyPair::getConfigKeyPair)
.map(ConfigKeyPair::getPassword)
.collect(Collectors.toList());

final List<KeyData> newKeyData =
newConfigKeyPairs.stream().map(keyDataMarshaller::marshal).collect(Collectors.toList());

if (Objects.isNull(fileUpdateOptions)) {
return new CliResult(0, true, null);
}

final List<KeyData> newKeyData =
generatedKeyPairs.stream()
.map(GeneratedKeyPair::getConfigKeyPair)
.map(keyDataMarshaller::marshal)
.collect(Collectors.toList());

// prepare config for addition of new keys if required
prepareConfigForNewKeys(fileUpdateOptions.getConfig());

Expand All @@ -184,13 +266,4 @@ public CliResult call() throws IOException {

return new CliResult(0, true, fileUpdateOptions.getConfig());
}

static void prepareConfigForNewKeys(Config config) {
if (Objects.isNull(config.getKeys())) {
config.setKeys(new KeyConfiguration());
}
if (Objects.isNull(config.getKeys().getKeyData())) {
config.getKeys().setKeyData(new ArrayList<>());
}
}
}
Loading