mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 15:37:54 -05:00
Updated ATs DSL to create PKI QBFT node configuration (#2670)
Signed-off-by: Lucas Saldanha <lucascrsaldanha@gmail.com>
This commit is contained in:
@@ -14,6 +14,7 @@ dependencies {
|
||||
implementation project(':ethereum:eth')
|
||||
implementation project(':ethereum:p2p')
|
||||
implementation project(':pki')
|
||||
implementation project(path: ':pki', configuration: 'testArtifacts')
|
||||
implementation project(':ethereum:permissioning')
|
||||
implementation project(':ethereum:rlp')
|
||||
implementation project(':metrics:core')
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
|
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
|
||||
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
|
||||
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
|
||||
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.NodeConfiguration;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider;
|
||||
@@ -118,6 +119,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
|
||||
private final List<String> staticNodes;
|
||||
private boolean isDnsEnabled = false;
|
||||
private Optional<Integer> exitCode = Optional.empty();
|
||||
private Optional<PkiKeyStoreConfiguration> pkiKeyStoreConfiguration = Optional.empty();
|
||||
|
||||
public BesuNode(
|
||||
final String name,
|
||||
@@ -145,7 +147,8 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
|
||||
final boolean isDnsEnabled,
|
||||
final Optional<PrivacyParameters> privacyParameters,
|
||||
final List<String> runCommand,
|
||||
final Optional<KeyPair> keyPair)
|
||||
final Optional<KeyPair> keyPair,
|
||||
final Optional<PkiKeyStoreConfiguration> pkiKeyStoreConfiguration)
|
||||
throws IOException {
|
||||
this.homeDirectory = dataPath.orElseGet(BesuNode::createTmpDataDirectory);
|
||||
keyfilePath.ifPresent(
|
||||
@@ -195,6 +198,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
|
||||
this.staticNodes = staticNodes;
|
||||
this.isDnsEnabled = isDnsEnabled;
|
||||
privacyParameters.ifPresent(this::setPrivacyParameters);
|
||||
this.pkiKeyStoreConfiguration = pkiKeyStoreConfiguration;
|
||||
LOG.info("Created BesuNode {}", this.toString());
|
||||
}
|
||||
|
||||
@@ -656,6 +660,10 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
|
||||
return runCommand;
|
||||
}
|
||||
|
||||
public Optional<PkiKeyStoreConfiguration> getPkiKeyStoreConfiguration() {
|
||||
return pkiKeyStoreConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
|
||||
@@ -319,6 +319,34 @@ public class ProcessBesuNodeRunner implements BesuNodeRunner {
|
||||
String.valueOf(
|
||||
permissioningConfiguration.getNodeSmartContractInterfaceVersion()));
|
||||
});
|
||||
|
||||
node.getPkiKeyStoreConfiguration()
|
||||
.ifPresent(
|
||||
pkiConfig -> {
|
||||
params.add("--Xpki-block-creation-enabled");
|
||||
|
||||
params.add("--Xpki-block-creation-keystore-certificate-alias");
|
||||
params.add(pkiConfig.getCertificateAlias());
|
||||
|
||||
params.add("--Xpki-block-creation-keystore-type");
|
||||
params.add(pkiConfig.getKeyStoreType());
|
||||
|
||||
params.add("--Xpki-block-creation-keystore-file");
|
||||
params.add(pkiConfig.getKeyStorePath().toAbsolutePath().toString());
|
||||
|
||||
params.add("--Xpki-block-creation-keystore-password-file");
|
||||
params.add(pkiConfig.getKeyStorePasswordPath().toAbsolutePath().toString());
|
||||
|
||||
params.add("--Xpki-block-creation-truststore-type");
|
||||
params.add(pkiConfig.getTrustStoreType());
|
||||
|
||||
params.add("--Xpki-block-creation-truststore-file");
|
||||
params.add(pkiConfig.getTrustStorePath().toAbsolutePath().toString());
|
||||
|
||||
params.add("--Xpki-block-creation-truststore-password-file");
|
||||
params.add(pkiConfig.getTrustStorePasswordPath().toAbsolutePath().toString());
|
||||
});
|
||||
|
||||
params.addAll(node.getExtraCLIOptions());
|
||||
|
||||
params.add("--key-value-storage");
|
||||
|
||||
@@ -20,6 +20,7 @@ import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
|
||||
import org.hyperledger.besu.Runner;
|
||||
import org.hyperledger.besu.RunnerBuilder;
|
||||
import org.hyperledger.besu.cli.config.EthNetworkConfig;
|
||||
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfigurationProvider;
|
||||
import org.hyperledger.besu.controller.BesuController;
|
||||
import org.hyperledger.besu.controller.BesuControllerBuilder;
|
||||
import org.hyperledger.besu.crypto.KeyPairSecurityModule;
|
||||
@@ -163,6 +164,10 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
|
||||
.isRevertReasonEnabled(node.isRevertReasonEnabled())
|
||||
.storageProvider(storageProvider)
|
||||
.gasLimitCalculator(GasLimitCalculator.constant())
|
||||
.pkiBlockCreationConfiguration(
|
||||
node.getPkiKeyStoreConfiguration()
|
||||
.map(
|
||||
(pkiConfig) -> new PkiBlockCreationConfigurationProvider().load(pkiConfig)))
|
||||
.build();
|
||||
|
||||
final RunnerBuilder runnerBuilder = new RunnerBuilder();
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
|
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
|
||||
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
|
||||
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
|
||||
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@@ -58,6 +59,7 @@ public class BesuNodeConfiguration {
|
||||
private final List<String> runCommand;
|
||||
private final NetworkName network;
|
||||
private final Optional<KeyPair> keyPair;
|
||||
private final Optional<PkiKeyStoreConfiguration> pkiKeyStoreConfiguration;
|
||||
|
||||
BesuNodeConfiguration(
|
||||
final String name,
|
||||
@@ -85,7 +87,8 @@ public class BesuNodeConfiguration {
|
||||
final boolean isDnsEnabled,
|
||||
final Optional<PrivacyParameters> privacyParameters,
|
||||
final List<String> runCommand,
|
||||
final Optional<KeyPair> keyPair) {
|
||||
final Optional<KeyPair> keyPair,
|
||||
final Optional<PkiKeyStoreConfiguration> pkiKeyStoreConfiguration) {
|
||||
this.name = name;
|
||||
this.miningParameters = miningParameters;
|
||||
this.jsonRpcConfiguration = jsonRpcConfiguration;
|
||||
@@ -112,6 +115,7 @@ public class BesuNodeConfiguration {
|
||||
this.privacyParameters = privacyParameters;
|
||||
this.runCommand = runCommand;
|
||||
this.keyPair = keyPair;
|
||||
this.pkiKeyStoreConfiguration = pkiKeyStoreConfiguration;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -217,4 +221,8 @@ public class BesuNodeConfiguration {
|
||||
public Optional<KeyPair> getKeyPair() {
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
public Optional<PkiKeyStoreConfiguration> getPkiKeyStoreConfiguration() {
|
||||
return pkiKeyStoreConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
|
||||
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
|
||||
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
|
||||
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
|
||||
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
|
||||
import org.hyperledger.besu.pki.keystore.KeyStoreWrapper;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationProvider;
|
||||
|
||||
@@ -80,6 +81,7 @@ public class BesuNodeConfigurationBuilder {
|
||||
private Optional<PrivacyParameters> privacyParameters = Optional.empty();
|
||||
private List<String> runCommand = new ArrayList<>();
|
||||
private Optional<KeyPair> keyPair = Optional.empty();
|
||||
private Optional<PkiKeyStoreConfiguration> pkiKeyStoreConfiguration = Optional.empty();
|
||||
|
||||
public BesuNodeConfigurationBuilder() {
|
||||
// Check connections more frequently during acceptance tests to cut down on
|
||||
@@ -349,6 +351,13 @@ public class BesuNodeConfigurationBuilder {
|
||||
return tempFile.toPath();
|
||||
}
|
||||
|
||||
public BesuNodeConfigurationBuilder pkiBlockCreationEnabled(
|
||||
final PkiKeyStoreConfiguration pkiKeyStoreConfiguration) {
|
||||
this.pkiKeyStoreConfiguration = Optional.of(pkiKeyStoreConfiguration);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public BesuNodeConfigurationBuilder discoveryEnabled(final boolean discoveryEnabled) {
|
||||
this.discoveryEnabled = discoveryEnabled;
|
||||
return this;
|
||||
@@ -433,6 +442,7 @@ public class BesuNodeConfigurationBuilder {
|
||||
isDnsEnabled,
|
||||
privacyParameters,
|
||||
runCommand,
|
||||
keyPair);
|
||||
keyPair,
|
||||
pkiKeyStoreConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.RunnableNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationFactory;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.pki.PkiKeystoreConfigurationFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -54,6 +55,8 @@ public class BesuNodeFactory {
|
||||
|
||||
private final GenesisConfigurationFactory genesis = new GenesisConfigurationFactory();
|
||||
private final NodeConfigurationFactory node = new NodeConfigurationFactory();
|
||||
private final PkiKeystoreConfigurationFactory pkiKeystoreConfigurationFactory =
|
||||
new PkiKeystoreConfigurationFactory();
|
||||
|
||||
public BesuNode create(final BesuNodeConfiguration config) throws IOException {
|
||||
return new BesuNode(
|
||||
@@ -82,7 +85,8 @@ public class BesuNodeFactory {
|
||||
config.isDnsEnabled(),
|
||||
config.getPrivacyParameters(),
|
||||
config.getRunCommand(),
|
||||
config.getKeyPair());
|
||||
config.getKeyPair(),
|
||||
config.getPkiKeyStoreConfiguration());
|
||||
}
|
||||
|
||||
public BesuNode createMinerNode(final String name) throws IOException {
|
||||
@@ -392,6 +396,19 @@ public class BesuNodeFactory {
|
||||
.build());
|
||||
}
|
||||
|
||||
public BesuNode createPkiQbftNode(final String name) throws IOException {
|
||||
return create(
|
||||
new BesuNodeConfigurationBuilder()
|
||||
.name(name)
|
||||
.miningEnabled()
|
||||
.jsonRpcConfiguration(node.createJsonRpcWithQbftEnabledConfig(false))
|
||||
.webSocketConfiguration(node.createWebSocketEnabledConfig())
|
||||
.devMode(false)
|
||||
.genesisConfigProvider(genesis::createQbftGenesisConfig)
|
||||
.pkiBlockCreationEnabled(pkiKeystoreConfigurationFactory.createPkiConfig())
|
||||
.build());
|
||||
}
|
||||
|
||||
public BesuNode createCustomGenesisNode(
|
||||
final String name, final String genesisPath, final boolean canBeBootnode) throws IOException {
|
||||
return createCustomGenesisNode(name, genesisPath, canBeBootnode, false);
|
||||
@@ -504,6 +521,24 @@ public class BesuNodeFactory {
|
||||
.build());
|
||||
}
|
||||
|
||||
public BesuNode createPkiQbftNodeWithValidators(final String name, final String... validators)
|
||||
throws IOException {
|
||||
|
||||
return create(
|
||||
new BesuNodeConfigurationBuilder()
|
||||
.name(name)
|
||||
.miningEnabled()
|
||||
.jsonRpcConfiguration(node.createJsonRpcWithQbftEnabledConfig(false))
|
||||
.webSocketConfiguration(node.createWebSocketEnabledConfig())
|
||||
.devMode(false)
|
||||
.pkiBlockCreationEnabled(pkiKeystoreConfigurationFactory.createPkiConfig())
|
||||
.genesisConfigProvider(
|
||||
nodes ->
|
||||
node.createGenesisConfigForValidators(
|
||||
asList(validators), nodes, genesis::createQbftGenesisConfig))
|
||||
.build());
|
||||
}
|
||||
|
||||
public BesuNode createNodeWithStaticNodes(final String name, final List<Node> staticNodes)
|
||||
throws IOException {
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed 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.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.hyperledger.besu.tests.acceptance.dsl.node.configuration.pki;
|
||||
|
||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.createKeyPair;
|
||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.createSelfSignedCertificate;
|
||||
import static org.hyperledger.besu.pki.util.TestCertificateUtils.issueCertificate;
|
||||
|
||||
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PkiKeystoreConfigurationFactory {
|
||||
|
||||
public static final String KEYSTORE_DEFAULT_TYPE = "PKCS12";
|
||||
public static final String KEYSTORE_DEFAULT_PASSWORD = "password";
|
||||
public static final String KEYSTORE_DEFAULT_CERT_ALIAS = "validator";
|
||||
|
||||
private KeyPair caKeyPair;
|
||||
private X509Certificate caCertificate;
|
||||
private Path trustStoreFile;
|
||||
private Path passwordFile;
|
||||
|
||||
public PkiKeyStoreConfiguration createPkiConfig() {
|
||||
PkiKeyStoreConfiguration.Builder pkiKeyStoreConfigBuilder =
|
||||
new PkiKeyStoreConfiguration.Builder();
|
||||
|
||||
pkiKeyStoreConfigBuilder.withTrustStoreType(KEYSTORE_DEFAULT_TYPE);
|
||||
pkiKeyStoreConfigBuilder.withTrustStorePath(createTrustStore());
|
||||
pkiKeyStoreConfigBuilder.withTrustStorePasswordPath(passwordFile);
|
||||
|
||||
pkiKeyStoreConfigBuilder.withKeyStoreType(KEYSTORE_DEFAULT_TYPE);
|
||||
pkiKeyStoreConfigBuilder.withKeyStorePath(createKeyStore());
|
||||
pkiKeyStoreConfigBuilder.withKeyStorePasswordPath(passwordFile);
|
||||
|
||||
pkiKeyStoreConfigBuilder.withCertificateAlias(KEYSTORE_DEFAULT_CERT_ALIAS);
|
||||
|
||||
return pkiKeyStoreConfigBuilder.build();
|
||||
}
|
||||
|
||||
private Path createTrustStore() {
|
||||
// Only create the truststore if this is the first time this method is being called
|
||||
if (caKeyPair == null) {
|
||||
try {
|
||||
caKeyPair = createKeyPair();
|
||||
caCertificate = createSelfSignedCertificate("ca", notBefore(), notAfter(), caKeyPair);
|
||||
|
||||
final KeyStore truststore = KeyStore.getInstance(KEYSTORE_DEFAULT_TYPE);
|
||||
truststore.load(null, null);
|
||||
truststore.setCertificateEntry("ca", caCertificate);
|
||||
|
||||
final String uniqueId = UUID.randomUUID().toString();
|
||||
trustStoreFile = writeKeyStoreFile(truststore, "truststore", uniqueId);
|
||||
passwordFile = writePasswordFile(KEYSTORE_DEFAULT_PASSWORD, "password", uniqueId);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Error creating truststore for Acceptance Test", e);
|
||||
}
|
||||
}
|
||||
|
||||
return trustStoreFile;
|
||||
}
|
||||
|
||||
private Path createKeyStore() {
|
||||
if (caKeyPair == null) {
|
||||
createTrustStore();
|
||||
}
|
||||
|
||||
final KeyPair kp = createKeyPair();
|
||||
final X509Certificate certificate =
|
||||
issueCertificate(caCertificate, caKeyPair, "validator", notBefore(), notAfter(), kp, false);
|
||||
|
||||
try {
|
||||
final KeyStore keyStore = KeyStore.getInstance(KEYSTORE_DEFAULT_TYPE);
|
||||
keyStore.load(null, null);
|
||||
keyStore.setKeyEntry(
|
||||
"validator",
|
||||
kp.getPrivate(),
|
||||
KEYSTORE_DEFAULT_PASSWORD.toCharArray(),
|
||||
new Certificate[] {certificate, caCertificate});
|
||||
|
||||
final String id = UUID.randomUUID().toString();
|
||||
return writeKeyStoreFile(keyStore, "keystore", id);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Error creating keystore for Acceptance Test", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path writeKeyStoreFile(
|
||||
final KeyStore keyStore, final String prefix, final String suffix) {
|
||||
try {
|
||||
final Path file = Files.createTempFile(prefix, suffix != null ? suffix : "");
|
||||
file.toFile().deleteOnExit();
|
||||
final FileOutputStream keyStoreFOS = new FileOutputStream(file.toFile());
|
||||
keyStore.store(keyStoreFOS, KEYSTORE_DEFAULT_PASSWORD.toCharArray());
|
||||
|
||||
return file;
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Error creating keystore file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path writePasswordFile(final String password, final String prefix, final String suffix) {
|
||||
try {
|
||||
final Path file = Files.createTempFile(prefix, suffix);
|
||||
file.toFile().deleteOnExit();
|
||||
Files.write(file, password.getBytes(StandardCharsets.UTF_8));
|
||||
return file;
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException("Error creating password file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Instant notBefore() {
|
||||
return Instant.now().minus(1, ChronoUnit.DAYS);
|
||||
}
|
||||
|
||||
private Instant notAfter() {
|
||||
return Instant.now().plus(10, ChronoUnit.DAYS);
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,7 @@ public class PrivacyNode implements AutoCloseable {
|
||||
besuConfig.isDnsEnabled(),
|
||||
besuConfig.getPrivacyParameters(),
|
||||
List.of(),
|
||||
Optional.empty(),
|
||||
Optional.empty());
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import static java.util.Arrays.asList;
|
||||
import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP;
|
||||
|
||||
import org.hyperledger.besu.cli.util.CommandLineUtils;
|
||||
import org.hyperledger.besu.ethereum.api.tls.FileBasedPasswordProvider;
|
||||
import org.hyperledger.besu.pki.config.PkiKeyStoreConfiguration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@@ -119,14 +118,11 @@ public class PkiBlockCreationOptions {
|
||||
new PkiKeyStoreConfiguration.Builder()
|
||||
.withKeyStoreType(keyStoreType)
|
||||
.withKeyStorePath(keyStoreFile)
|
||||
.withKeyStorePasswordSupplier(new FileBasedPasswordProvider(keyStorePasswordFile))
|
||||
.withKeyStorePasswordPath(keyStorePasswordFile)
|
||||
.withCertificateAlias(certificateAlias)
|
||||
.withTrustStoreType(trustStoreType)
|
||||
.withTrustStorePath(trustStoreFile)
|
||||
.withTrustStorePasswordSupplier(
|
||||
null == trustStorePasswordFile
|
||||
? null
|
||||
: new FileBasedPasswordProvider(trustStorePasswordFile))
|
||||
.withTrustStorePasswordPath(trustStorePasswordFile)
|
||||
.withCrlFilePath(crlFile)
|
||||
.build());
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.consensus.qbft.pki.PkiBlockCreationConfigurationProvider.KeyStoreWrapperProvider;
|
||||
@@ -48,14 +50,17 @@ public class PkiBlockCreationConfigurationProviderTest {
|
||||
.thenReturn(trustStoreWrapper);
|
||||
|
||||
final PkiKeyStoreConfiguration pkiKeyStoreConfiguration =
|
||||
new PkiKeyStoreConfiguration.Builder()
|
||||
.withKeyStorePath(Path.of("/tmp/keystore"))
|
||||
.withKeyStorePasswordSupplier(() -> "pwd")
|
||||
.withTrustStorePath(Path.of("/tmp/truststore"))
|
||||
.withTrustStorePasswordSupplier(() -> "pwd")
|
||||
.withCertificateAlias("anAlias")
|
||||
.withCrlFilePath(Path.of("/tmp/crl"))
|
||||
.build();
|
||||
spy(
|
||||
new PkiKeyStoreConfiguration.Builder()
|
||||
.withKeyStorePath(Path.of("/tmp/keystore"))
|
||||
.withKeyStorePasswordPath(Path.of("/tmp/password"))
|
||||
.withTrustStorePath(Path.of("/tmp/truststore"))
|
||||
.withTrustStorePasswordPath(Path.of("/tmp/password"))
|
||||
.withCertificateAlias("anAlias")
|
||||
.withCrlFilePath(Path.of("/tmp/crl"))
|
||||
.build());
|
||||
doReturn("pwd").when(pkiKeyStoreConfiguration).getKeyStorePassword();
|
||||
doReturn("pwd").when(pkiKeyStoreConfiguration).getTrustStorePassword();
|
||||
|
||||
final PkiBlockCreationConfigurationProvider pkiBlockCreationConfigProvider =
|
||||
new PkiBlockCreationConfigurationProvider(keyStoreWrapperProvider);
|
||||
|
||||
@@ -38,3 +38,13 @@ dependencies {
|
||||
testImplementation 'org.mockito:mockito-core'
|
||||
testImplementation 'org.apache.logging.log4j:log4j-core'
|
||||
}
|
||||
|
||||
configurations { testArtifacts }
|
||||
task testJar(type: Jar) {
|
||||
archiveBaseName = "${project.name}-test"
|
||||
from sourceSets.test.output
|
||||
}
|
||||
|
||||
artifacts {
|
||||
testArtifacts testJar
|
||||
}
|
||||
|
||||
@@ -16,9 +16,13 @@ package org.hyperledger.besu.pki.config;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
public class PkiKeyStoreConfiguration {
|
||||
|
||||
@@ -27,29 +31,29 @@ public class PkiKeyStoreConfiguration {
|
||||
|
||||
private final String keyStoreType;
|
||||
private final Path keyStorePath;
|
||||
private final Supplier<String> keyStorePasswordSupplier;
|
||||
private final Path keyStorePasswordPath;
|
||||
private final String certificateAlias;
|
||||
private final String trustStoreType;
|
||||
private final Path trustStorePath;
|
||||
private final Supplier<String> trustStorePasswordSupplier;
|
||||
private final Path trustStorePasswordPath;
|
||||
private final Optional<Path> crlFilePath;
|
||||
|
||||
public PkiKeyStoreConfiguration(
|
||||
final String keyStoreType,
|
||||
final Path keyStorePath,
|
||||
final Supplier<String> keyStorePasswordSupplier,
|
||||
final Path keyStorePasswordPath,
|
||||
final String certificateAlias,
|
||||
final String trustStoreType,
|
||||
final Path trustStorePath,
|
||||
final Supplier<String> trustStorePasswordSupplier,
|
||||
final Path trustStorePasswordPath,
|
||||
final Optional<Path> crlFilePath) {
|
||||
this.keyStoreType = keyStoreType;
|
||||
this.keyStorePath = keyStorePath;
|
||||
this.keyStorePasswordSupplier = keyStorePasswordSupplier;
|
||||
this.keyStorePasswordPath = keyStorePasswordPath;
|
||||
this.certificateAlias = certificateAlias;
|
||||
this.trustStoreType = trustStoreType;
|
||||
this.trustStorePath = trustStorePath;
|
||||
this.trustStorePasswordSupplier = trustStorePasswordSupplier;
|
||||
this.trustStorePasswordPath = trustStorePasswordPath;
|
||||
this.crlFilePath = crlFilePath;
|
||||
}
|
||||
|
||||
@@ -61,8 +65,13 @@ public class PkiKeyStoreConfiguration {
|
||||
return keyStorePath;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Path getKeyStorePasswordPath() {
|
||||
return keyStorePasswordPath;
|
||||
}
|
||||
|
||||
public String getKeyStorePassword() {
|
||||
return null == keyStorePasswordSupplier ? null : keyStorePasswordSupplier.get();
|
||||
return readPasswordFromFile(keyStorePasswordPath);
|
||||
}
|
||||
|
||||
public String getCertificateAlias() {
|
||||
@@ -77,8 +86,13 @@ public class PkiKeyStoreConfiguration {
|
||||
return trustStorePath;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Path getTrustStorePasswordPath() {
|
||||
return trustStorePasswordPath;
|
||||
}
|
||||
|
||||
public String getTrustStorePassword() {
|
||||
return trustStorePasswordSupplier.get();
|
||||
return readPasswordFromFile(trustStorePasswordPath);
|
||||
}
|
||||
|
||||
public Optional<Path> getCrlFilePath() {
|
||||
@@ -89,11 +103,11 @@ public class PkiKeyStoreConfiguration {
|
||||
|
||||
private String keyStoreType = DEFAULT_KEYSTORE_TYPE;
|
||||
private Path keyStorePath;
|
||||
private Supplier<String> keyStorePasswordSupplier;
|
||||
private Path keyStorePasswordPath;
|
||||
private String certificateAlias = DEFAULT_CERTIFICATE_ALIAS;
|
||||
private String trustStoreType = DEFAULT_KEYSTORE_TYPE;
|
||||
private Path trustStorePath;
|
||||
private Supplier<String> trustStorePasswordSupplier;
|
||||
private Path trustStorePasswordPath;
|
||||
private Path crlFilePath;
|
||||
|
||||
public Builder() {}
|
||||
@@ -108,8 +122,8 @@ public class PkiKeyStoreConfiguration {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withKeyStorePasswordSupplier(final Supplier<String> keyStorePasswordSupplier) {
|
||||
this.keyStorePasswordSupplier = keyStorePasswordSupplier;
|
||||
public Builder withKeyStorePasswordPath(final Path keyStorePasswordPath) {
|
||||
this.keyStorePasswordPath = keyStorePasswordPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -128,9 +142,8 @@ public class PkiKeyStoreConfiguration {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withTrustStorePasswordSupplier(
|
||||
final Supplier<String> trustStorePasswordSupplier) {
|
||||
this.trustStorePasswordSupplier = trustStorePasswordSupplier;
|
||||
public Builder withTrustStorePasswordPath(final Path trustStorePasswordPath) {
|
||||
this.trustStorePasswordPath = trustStorePasswordPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -141,16 +154,29 @@ public class PkiKeyStoreConfiguration {
|
||||
|
||||
public PkiKeyStoreConfiguration build() {
|
||||
requireNonNull(keyStoreType, "Key Store Type must not be null");
|
||||
requireNonNull(keyStorePasswordSupplier, "Key Store password supplier must not be null");
|
||||
requireNonNull(keyStorePasswordPath, "Key Store password file must not be null");
|
||||
|
||||
return new PkiKeyStoreConfiguration(
|
||||
keyStoreType,
|
||||
keyStorePath,
|
||||
keyStorePasswordSupplier,
|
||||
keyStorePasswordPath,
|
||||
certificateAlias,
|
||||
trustStoreType,
|
||||
trustStorePath,
|
||||
trustStorePasswordSupplier,
|
||||
trustStorePasswordPath,
|
||||
Optional.ofNullable(crlFilePath));
|
||||
}
|
||||
}
|
||||
|
||||
private String readPasswordFromFile(final Path passwordFile) {
|
||||
try (final Stream<String> fileStream = Files.lines(passwordFile)) {
|
||||
return fileStream.findFirst().orElseThrow(() -> errorReadingFileException(passwordFile));
|
||||
} catch (final IOException e) {
|
||||
throw errorReadingFileException(passwordFile);
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeException errorReadingFileException(final Path path) {
|
||||
return new RuntimeException(String.format("Unable to read keystore password from %s", path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,8 @@ public class SoftwareKeyStoreWrapper extends AbstractKeyStoreWrapper {
|
||||
}
|
||||
return certificateChain;
|
||||
} catch (final Exception e) {
|
||||
throw new PkiException("Failed to certificate chain for alias: " + certificateAlias, e);
|
||||
throw new PkiException(
|
||||
"Failed to retrieve certificate chain for alias: " + certificateAlias, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user