mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
ENT-1661 Doorman crashes ungracefully when started with incorrect or … (#747)
* ENT-1661 Doorman crashes ungracefully when started with incorrect or no program arguments. Should display a meaningful message instead.
This commit is contained in:
parent
b3a4e3907f
commit
57291c435c
@ -68,6 +68,8 @@ publish {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':node')
|
compile project(':node')
|
||||||
|
// TODO: remove this when ArgsParser is moved into corda.
|
||||||
|
compile project(':network-management')
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testCompile "org.assertj:assertj-core:${assertj_version}"
|
testCompile "org.assertj:assertj-core:${assertj_version}"
|
||||||
}
|
}
|
||||||
|
@ -1,75 +1,61 @@
|
|||||||
package com.r3.corda.networkmanage.registration
|
package com.r3.corda.networkmanage.registration
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.utils.ArgsParser
|
||||||
import com.r3.corda.networkmanage.registration.ToolOption.KeyCopierOption
|
import com.r3.corda.networkmanage.registration.ToolOption.KeyCopierOption
|
||||||
import com.r3.corda.networkmanage.registration.ToolOption.RegistrationOption
|
import com.r3.corda.networkmanage.registration.ToolOption.RegistrationOption
|
||||||
import joptsimple.OptionParser
|
import joptsimple.OptionSet
|
||||||
import joptsimple.OptionSpecBuilder
|
import joptsimple.OptionSpecBuilder
|
||||||
import joptsimple.util.PathConverter
|
import joptsimple.util.PathConverter
|
||||||
import joptsimple.util.PathProperties
|
import joptsimple.util.PathProperties
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
Crypto.registerProviders() // Required to register Providers first thing on boot.
|
Crypto.registerProviders() // Required to register Providers first thing on boot.
|
||||||
val options = try {
|
val options = ToolArgsParser().parseOrExit(*args, printHelpOn = System.out)
|
||||||
parseOptions(*args)
|
|
||||||
} catch (e: ShowHelpException) {
|
|
||||||
e.errorMessage?.let(::println)
|
|
||||||
e.parser.printHelpOn(System.out)
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
when (options) {
|
when (options) {
|
||||||
is RegistrationOption -> options.runRegistration()
|
is RegistrationOption -> options.runRegistration()
|
||||||
is KeyCopierOption -> options.copyKeystore()
|
is KeyCopierOption -> options.copyKeystore()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseOptions(vararg args: String): ToolOption {
|
class ToolArgsParser : ArgsParser<ToolOption>() {
|
||||||
val optionParser = OptionParser()
|
private val importKeyStoreArg = optionParser.accepts("importkeystore")
|
||||||
val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp()
|
|
||||||
|
|
||||||
val importKeyStoreArg = optionParser.accepts("importkeystore")
|
private val configFileArg = optionParser
|
||||||
|
|
||||||
val configFileArg = optionParser
|
|
||||||
.accepts("config-file", "Path to the registration config file")
|
.accepts("config-file", "Path to the registration config file")
|
||||||
.availableUnless(importKeyStoreArg)
|
.availableUnless(importKeyStoreArg)
|
||||||
.requiredUnless(importKeyStoreArg)
|
.requiredUnless(importKeyStoreArg)
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
||||||
|
|
||||||
// key copy tool args
|
// key copy tool args
|
||||||
val destKeystorePathArg = optionParser.accepts("destkeystore", "Path to the destination keystore which the private key should be copied to")
|
private val destKeystorePathArg = optionParser.accepts("destkeystore", "Path to the destination keystore which the private key should be copied to")
|
||||||
.requireOnlyIf(importKeyStoreArg)
|
.requireOnlyIf(importKeyStoreArg)
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
||||||
|
|
||||||
val srcKeystorePathArg = optionParser.accepts("srckeystore", "Path to the source keystore containing the private key")
|
private val srcKeystorePathArg = optionParser.accepts("srckeystore", "Path to the source keystore containing the private key")
|
||||||
.requireOnlyIf(importKeyStoreArg)
|
.requireOnlyIf(importKeyStoreArg)
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
||||||
|
|
||||||
val destPasswordArg = optionParser.accepts("deststorepass", "Source keystore password. Read in from the console if not specified.")
|
private val destPasswordArg = optionParser.accepts("deststorepass", "Source keystore password. Read in from the console if not specified.")
|
||||||
.availableIf(importKeyStoreArg)
|
.availableIf(importKeyStoreArg)
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
|
|
||||||
val srcPasswordArg = optionParser.accepts("srcstorepass", "Destination keystore password. Read in from the console if not specified.")
|
private val srcPasswordArg = optionParser.accepts("srcstorepass", "Destination keystore password. Read in from the console if not specified.")
|
||||||
.availableIf(importKeyStoreArg)
|
.availableIf(importKeyStoreArg)
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
|
|
||||||
val destAliasArg = optionParser.accepts("destalias", "The alias under which the private key will be stored in the destination key store. If not provided then [srcalias] is used.")
|
private val destAliasArg = optionParser.accepts("destalias", "The alias under which the private key will be stored in the destination key store. If not provided then [srcalias] is used.")
|
||||||
.availableIf(importKeyStoreArg)
|
.availableIf(importKeyStoreArg)
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
|
|
||||||
val srcAliasArg = optionParser.accepts("srcalias", "The alias under which the private key resides in the source key store")
|
private val srcAliasArg = optionParser.accepts("srcalias", "The alias under which the private key resides in the source key store")
|
||||||
.requireOnlyIf(importKeyStoreArg)
|
.requireOnlyIf(importKeyStoreArg)
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
|
|
||||||
val optionSet = optionParser.parse(*args)
|
override fun parse(optionSet: OptionSet): ToolOption {
|
||||||
if (optionSet.has(helpOption)) {
|
|
||||||
throw ShowHelpException(optionParser)
|
|
||||||
}
|
|
||||||
|
|
||||||
val isCopyKey = optionSet.has(importKeyStoreArg)
|
val isCopyKey = optionSet.has(importKeyStoreArg)
|
||||||
return if (isCopyKey) {
|
return if (isCopyKey) {
|
||||||
val srcKeystorePath = optionSet.valueOf(srcKeystorePathArg)
|
val srcKeystorePath = optionSet.valueOf(srcKeystorePathArg)
|
||||||
@ -84,6 +70,7 @@ fun parseOptions(vararg args: String): ToolOption {
|
|||||||
RegistrationOption(configFile)
|
RegistrationOption(configFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun OptionSpecBuilder.requireOnlyIf(option: OptionSpecBuilder): OptionSpecBuilder = requiredIf(option).availableIf(option)
|
private fun OptionSpecBuilder.requireOnlyIf(option: OptionSpecBuilder): OptionSpecBuilder = requiredIf(option).availableIf(option)
|
||||||
|
|
||||||
@ -97,8 +84,6 @@ sealed class ToolOption {
|
|||||||
val destinationAlias: String?) : ToolOption()
|
val destinationAlias: String?) : ToolOption()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShowHelpException(val parser: OptionParser, val errorMessage: String? = null) : Exception()
|
|
||||||
|
|
||||||
fun readPassword(fmt: String): String {
|
fun readPassword(fmt: String): String {
|
||||||
return if (System.console() != null) {
|
return if (System.console() != null) {
|
||||||
String(System.console().readPassword(fmt))
|
String(System.console().readPassword(fmt))
|
||||||
|
@ -27,7 +27,7 @@ class OptionParserTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `parse registration args correctly`() {
|
fun `parse registration args correctly`() {
|
||||||
val options = parseOptions("--config-file", "${tempDir / "test.file"}") as ToolOption.RegistrationOption
|
val options = ToolArgsParser().parseOrExit("--config-file", "${tempDir / "test.file"}") as ToolOption.RegistrationOption
|
||||||
assertThat(options.configFile).isEqualTo(tempDir / "test.file")
|
assertThat(options.configFile).isEqualTo(tempDir / "test.file")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class OptionParserTest {
|
|||||||
"--destkeystore", "${tempDir / "target.jks"}",
|
"--destkeystore", "${tempDir / "target.jks"}",
|
||||||
"--deststorepass", "password2",
|
"--deststorepass", "password2",
|
||||||
"--srcalias", "testalias")
|
"--srcalias", "testalias")
|
||||||
assertThatThrownBy { parseOptions(*keyCopyArgs, "--config-file", "test.file") }
|
assertThatThrownBy { ToolArgsParser().parseOrExit(*keyCopyArgs, "--config-file", "test.file", printHelpOn = null) }
|
||||||
.isInstanceOf(OptionException::class.java)
|
.isInstanceOf(OptionException::class.java)
|
||||||
.hasMessageContaining("Option(s) [config-file] are unavailable given other options on the command line")
|
.hasMessageContaining("Option(s) [config-file] are unavailable given other options on the command line")
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ class OptionParserTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `key copy args should be unavailable in registration mode`() {
|
fun `key copy args should be unavailable in registration mode`() {
|
||||||
assertThatThrownBy {
|
assertThatThrownBy {
|
||||||
parseOptions("--config-file", "${tempDir / "test.file"}", "--srckeystore", "${tempDir / "source.jks"}")
|
ToolArgsParser().parseOrExit("--config-file", "${tempDir / "test.file"}", "--srckeystore", "${tempDir / "source.jks"}", printHelpOn = null)
|
||||||
}.isInstanceOf(OptionException::class.java)
|
}.isInstanceOf(OptionException::class.java)
|
||||||
.hasMessageContaining("Option(s) [srckeystore] are unavailable given other options on the command line")
|
.hasMessageContaining("Option(s) [srckeystore] are unavailable given other options on the command line")
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ class OptionParserTest {
|
|||||||
"--deststorepass", "password2",
|
"--deststorepass", "password2",
|
||||||
"--srcalias", "testalias",
|
"--srcalias", "testalias",
|
||||||
"--destalias", "testalias2")
|
"--destalias", "testalias2")
|
||||||
assertThat(parseOptions(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption(
|
assertThat(ToolArgsParser().parseOrExit(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption(
|
||||||
sourceFile = tempDir / "source.jks",
|
sourceFile = tempDir / "source.jks",
|
||||||
destinationFile = tempDir / "target.jks",
|
destinationFile = tempDir / "target.jks",
|
||||||
sourcePassword = "password1",
|
sourcePassword = "password1",
|
||||||
@ -80,7 +80,7 @@ class OptionParserTest {
|
|||||||
"--srckeystore", "${tempDir / "source.jks"}",
|
"--srckeystore", "${tempDir / "source.jks"}",
|
||||||
"--destkeystore", "${tempDir / "target.jks"}",
|
"--destkeystore", "${tempDir / "target.jks"}",
|
||||||
"--srcalias", "testalias")
|
"--srcalias", "testalias")
|
||||||
assertThat(parseOptions(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption(
|
assertThat(ToolArgsParser().parseOrExit(*keyCopyArgs)).isEqualTo(ToolOption.KeyCopierOption(
|
||||||
sourceFile = tempDir / "source.jks",
|
sourceFile = tempDir / "source.jks",
|
||||||
destinationFile = tempDir / "target.jks",
|
destinationFile = tempDir / "target.jks",
|
||||||
sourcePassword = null,
|
sourcePassword = null,
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.r3.corda.networkmanage.common.configuration
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.utils.ArgsParser
|
||||||
|
import joptsimple.OptionSet
|
||||||
|
import joptsimple.util.PathConverter
|
||||||
|
import joptsimple.util.PathProperties
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses key generator command line options.
|
||||||
|
*/
|
||||||
|
class ConfigFilePathArgsParser : ArgsParser<Path>() {
|
||||||
|
private val configFileArg = optionParser
|
||||||
|
.accepts("config-file", "The path to the config file")
|
||||||
|
.withRequiredArg()
|
||||||
|
.required()
|
||||||
|
.describedAs("filepath")
|
||||||
|
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
||||||
|
|
||||||
|
override fun parse(optionSet: OptionSet): Path {
|
||||||
|
return optionSet.valueOf(configFileArg).toAbsolutePath()
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
package com.r3.corda.networkmanage.common.configuration
|
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
|
||||||
import joptsimple.OptionParser
|
|
||||||
import joptsimple.util.PathConverter
|
|
||||||
import joptsimple.util.PathProperties
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses key generator command line options.
|
|
||||||
*/
|
|
||||||
fun parseCommandLine(vararg args: String): Path {
|
|
||||||
val optionParser = OptionParser()
|
|
||||||
val configFileArg = optionParser
|
|
||||||
.accepts("config-file", "The path to the config file")
|
|
||||||
.withRequiredArg()
|
|
||||||
.required()
|
|
||||||
.describedAs("filepath")
|
|
||||||
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
|
||||||
val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp()
|
|
||||||
|
|
||||||
val optionSet = optionParser.parse(*args)
|
|
||||||
// Print help and exit on help option or if there are missing options.
|
|
||||||
if (optionSet.has(helpOption) || !optionSet.has(configFileArg)) {
|
|
||||||
throw ShowHelpException(optionParser)
|
|
||||||
}
|
|
||||||
return optionSet.valueOf(configFileArg).toAbsolutePath()
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.r3.corda.networkmanage.common.utils
|
||||||
|
|
||||||
|
import joptsimple.OptionException
|
||||||
|
import joptsimple.OptionParser
|
||||||
|
import joptsimple.OptionSet
|
||||||
|
import java.io.PrintStream
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
// TODO: This class could be useful for the rest of the codebase.
|
||||||
|
abstract class ArgsParser<out T : Any> {
|
||||||
|
protected val optionParser = OptionParser()
|
||||||
|
private val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp()
|
||||||
|
|
||||||
|
/**
|
||||||
|
If [printHelpOn] output stream is not null, this method will print help message and exit process
|
||||||
|
when encountered any error during args parsing, or when help flag is set.
|
||||||
|
*/
|
||||||
|
fun parseOrExit(vararg args: String, printHelpOn: PrintStream? = System.out): T {
|
||||||
|
val optionSet = try {
|
||||||
|
optionParser.parse(*args)
|
||||||
|
} catch (e: OptionException) {
|
||||||
|
printHelpOn?.let {
|
||||||
|
it.println(e.message ?: "Unable to parse arguments.")
|
||||||
|
optionParser.printHelpOn(it)
|
||||||
|
exitProcess(-1)
|
||||||
|
}
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
if (optionSet.has(helpOption)) {
|
||||||
|
printHelpOn?.let(optionParser::printHelpOn)
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
return parse(optionSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun parse(optionSet: OptionSet): T
|
||||||
|
}
|
@ -13,9 +13,7 @@ package com.r3.corda.networkmanage.common.utils
|
|||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigParseOptions
|
import com.typesafe.config.ConfigParseOptions
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
import com.typesafe.config.ConfigRenderOptions
|
||||||
import joptsimple.OptionParser
|
|
||||||
import net.corda.core.CordaOID
|
import net.corda.core.CordaOID
|
||||||
import net.corda.core.crypto.sha256
|
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.CertRole
|
||||||
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
import net.corda.core.serialization.internal.SerializationEnvironmentImpl
|
||||||
import net.corda.core.serialization.internal.nodeSerializationEnv
|
import net.corda.core.serialization.internal.nodeSerializationEnv
|
||||||
@ -34,7 +32,6 @@ import org.slf4j.LoggerFactory
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
import java.security.PublicKey
|
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
|
|
||||||
@ -52,8 +49,6 @@ inline fun <reified T : Any> parseConfig(file: Path): T {
|
|||||||
return config.parseAs(strict = false)
|
return config.parseAs(strict = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShowHelpException(val parser: OptionParser, val errorMessage: String? = null) : Exception()
|
|
||||||
|
|
||||||
fun buildCertPath(certPathBytes: ByteArray): CertPath = X509CertificateFactory().delegate.generateCertPath(certPathBytes.inputStream())
|
fun buildCertPath(certPathBytes: ByteArray): CertPath = X509CertificateFactory().delegate.generateCertPath(certPathBytes.inputStream())
|
||||||
|
|
||||||
fun X509KeyStore.getCertPathAndKey(alias: String, privateKeyPassword: String): CertPathAndKey {
|
fun X509KeyStore.getCertPathAndKey(alias: String, privateKeyPassword: String): CertPathAndKey {
|
||||||
|
@ -38,8 +38,7 @@ fun parseParameters(configFile: Path?): GeneratorConfiguration {
|
|||||||
return if (configFile == null) {
|
return if (configFile == null) {
|
||||||
GeneratorConfiguration()
|
GeneratorConfiguration()
|
||||||
} else {
|
} else {
|
||||||
ConfigFactory
|
ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(true))
|
||||||
.parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(true))
|
|
||||||
.resolve()
|
.resolve()
|
||||||
.parseAs()
|
.parseAs()
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.dev
|
package com.r3.corda.networkmanage.dev
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.configuration.parseCommandLine
|
import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser
|
||||||
import com.r3.corda.networkmanage.doorman.CORDA_X500_BASE
|
import com.r3.corda.networkmanage.doorman.CORDA_X500_BASE
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.internal.createDirectories
|
import net.corda.core.internal.createDirectories
|
||||||
@ -34,7 +34,7 @@ private val logger = LogManager.getLogger("com.r3.corda.networkmanage.dev.Main")
|
|||||||
* Look for the 'certificates' directory.
|
* Look for the 'certificates' directory.
|
||||||
*/
|
*/
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
run(parseParameters(parseCommandLine(*args)))
|
run(parseParameters(ConfigFilePathArgsParser().parseOrExit(*args)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun run(configuration: GeneratorConfiguration) {
|
fun run(configuration: GeneratorConfiguration) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.r3.corda.networkmanage.doorman
|
package com.r3.corda.networkmanage.doorman
|
||||||
|
|
||||||
import com.google.common.primitives.Booleans
|
import com.google.common.primitives.Booleans
|
||||||
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
import com.r3.corda.networkmanage.common.utils.ArgsParser
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigParseOptions
|
import com.typesafe.config.ConfigParseOptions
|
||||||
import joptsimple.OptionParser
|
import joptsimple.OptionSet
|
||||||
import joptsimple.util.EnumConverter
|
import joptsimple.util.EnumConverter
|
||||||
import joptsimple.util.PathConverter
|
import joptsimple.util.PathConverter
|
||||||
import joptsimple.util.PathProperties
|
import joptsimple.util.PathProperties
|
||||||
@ -14,9 +14,7 @@ import net.corda.nodeapi.internal.config.parseAs
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
class DoormanArgsParser {
|
class DoormanArgsParser : ArgsParser<DoormanCmdLineOptions>() {
|
||||||
private val optionParser = OptionParser()
|
|
||||||
private val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp()
|
|
||||||
private val configFileArg = optionParser
|
private val configFileArg = optionParser
|
||||||
.accepts("config-file", "The path to the config file")
|
.accepts("config-file", "The path to the config file")
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
@ -37,11 +35,7 @@ class DoormanArgsParser {
|
|||||||
.accepts("trust-store-password", "Password for the generated network root trust store. Only applicable when operating in ${Mode.ROOT_KEYGEN} mode.")
|
.accepts("trust-store-password", "Password for the generated network root trust store. Only applicable when operating in ${Mode.ROOT_KEYGEN} mode.")
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
|
|
||||||
fun parse(vararg args: String): DoormanCmdLineOptions {
|
override fun parse(optionSet: OptionSet): DoormanCmdLineOptions {
|
||||||
val optionSet = optionParser.parse(*args)
|
|
||||||
if (optionSet.has(helpOption)) {
|
|
||||||
throw ShowHelpException(optionParser)
|
|
||||||
}
|
|
||||||
val configFile = optionSet.valueOf(configFileArg)
|
val configFile = optionSet.valueOf(configFileArg)
|
||||||
val mode = optionSet.valueOf(modeArg)
|
val mode = optionSet.valueOf(modeArg)
|
||||||
val setNetworkParametersFile = optionSet.valueOf(setNetworkParametersArg)
|
val setNetworkParametersFile = optionSet.valueOf(setNetworkParametersArg)
|
||||||
|
@ -31,13 +31,7 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initialiseSerialization()
|
initialiseSerialization()
|
||||||
val cmdLineOptions = try {
|
val cmdLineOptions = DoormanArgsParser().parseOrExit(*args)
|
||||||
DoormanArgsParser().parse(*args)
|
|
||||||
} catch (e: ShowHelpException) {
|
|
||||||
e.errorMessage?.let(::println)
|
|
||||||
e.parser.printHelpOn(System.out)
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val config = parseConfig<NetworkManagementServerConfig>(cmdLineOptions.configFile)
|
val config = parseConfig<NetworkManagementServerConfig>(cmdLineOptions.configFile)
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ package com.r3.corda.networkmanage.hsm
|
|||||||
|
|
||||||
import com.jcabi.manifests.Manifests
|
import com.jcabi.manifests.Manifests
|
||||||
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
||||||
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
|
||||||
import com.r3.corda.networkmanage.common.utils.initialiseSerialization
|
import com.r3.corda.networkmanage.common.utils.initialiseSerialization
|
||||||
import com.r3.corda.networkmanage.common.utils.parseConfig
|
import com.r3.corda.networkmanage.common.utils.parseConfig
|
||||||
import com.r3.corda.networkmanage.hsm.configuration.ManualMode
|
import com.r3.corda.networkmanage.hsm.configuration.ManualMode
|
||||||
@ -25,7 +24,6 @@ import org.apache.logging.log4j.LogManager
|
|||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
import java.security.Security
|
import java.security.Security
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import kotlin.system.exitProcess
|
|
||||||
|
|
||||||
private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.Main")
|
private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.Main")
|
||||||
|
|
||||||
@ -34,13 +32,7 @@ fun main(args: Array<String>) {
|
|||||||
println("Signing Service Version: ${Manifests.read("Signing-Service-Version")}")
|
println("Signing Service Version: ${Manifests.read("Signing-Service-Version")}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val cmdLineOptions = try {
|
val cmdLineOptions = SigningServiceArgsParser().parseOrExit(*args)
|
||||||
SigningServiceArgsParser().parse(*args)
|
|
||||||
} catch (e: ShowHelpException) {
|
|
||||||
e.errorMessage?.let(::println)
|
|
||||||
e.parser.printHelpOn(System.out)
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val config = parseConfig<SigningServiceConfig>(cmdLineOptions.configFile)
|
val config = parseConfig<SigningServiceConfig>(cmdLineOptions.configFile)
|
||||||
|
|
||||||
|
@ -11,20 +11,15 @@
|
|||||||
package com.r3.corda.networkmanage.hsm.configuration
|
package com.r3.corda.networkmanage.hsm.configuration
|
||||||
|
|
||||||
import com.google.common.primitives.Booleans
|
import com.google.common.primitives.Booleans
|
||||||
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
import com.r3.corda.networkmanage.common.utils.ArgsParser
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.AuthMode
|
import com.r3.corda.networkmanage.hsm.authentication.AuthMode
|
||||||
import com.typesafe.config.ConfigFactory
|
import joptsimple.OptionSet
|
||||||
import com.typesafe.config.ConfigParseOptions
|
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
|
||||||
import joptsimple.OptionParser
|
|
||||||
import joptsimple.util.PathConverter
|
import joptsimple.util.PathConverter
|
||||||
import joptsimple.util.PathProperties
|
import joptsimple.util.PathProperties
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.nodeapi.internal.config.parseAs
|
|
||||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import java.net.InetAddress
|
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -84,9 +79,7 @@ data class AuthParametersConfig(val mode: AuthMode,
|
|||||||
val keyFilePath: Path? = null,
|
val keyFilePath: Path? = null,
|
||||||
val threshold: Int)
|
val threshold: Int)
|
||||||
|
|
||||||
class SigningServiceArgsParser {
|
class SigningServiceArgsParser : ArgsParser<SigningServiceCmdLineOptions>() {
|
||||||
private val optionParser = OptionParser()
|
|
||||||
private val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp()
|
|
||||||
private val baseDirArg = optionParser
|
private val baseDirArg = optionParser
|
||||||
.accepts("basedir", "Overriding configuration filepath, default to current directory.")
|
.accepts("basedir", "Overriding configuration filepath, default to current directory.")
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
@ -97,11 +90,7 @@ class SigningServiceArgsParser {
|
|||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
.withValuesConvertedBy(PathConverter(PathProperties.FILE_EXISTING))
|
||||||
|
|
||||||
fun parse(vararg args: String): SigningServiceCmdLineOptions {
|
override fun parse(optionSet: OptionSet): SigningServiceCmdLineOptions {
|
||||||
val optionSet = optionParser.parse(*args)
|
|
||||||
if (optionSet.has(helpOption)) {
|
|
||||||
throw ShowHelpException(optionParser)
|
|
||||||
}
|
|
||||||
val baseDir = optionSet.valueOf(baseDirArg)
|
val baseDir = optionSet.valueOf(baseDirArg)
|
||||||
val configFile = optionSet.valueOf(configFileArg) ?: baseDir / "signing_service.conf"
|
val configFile = optionSet.valueOf(configFileArg) ?: baseDir / "signing_service.conf"
|
||||||
return SigningServiceCmdLineOptions(baseDir, configFile)
|
return SigningServiceCmdLineOptions(baseDir, configFile)
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.hsm.generator
|
package com.r3.corda.networkmanage.hsm.generator
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.configuration.parseCommandLine
|
import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser
|
||||||
import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig
|
import com.r3.corda.networkmanage.hsm.authentication.CryptoServerProviderConfig
|
||||||
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
|
import com.r3.corda.networkmanage.hsm.utils.mapCryptoServerException
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType.ROOT_CA
|
import net.corda.nodeapi.internal.crypto.CertificateType.ROOT_CA
|
||||||
@ -19,7 +19,7 @@ import org.apache.logging.log4j.LogManager
|
|||||||
private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.Main")
|
private val logger = LogManager.getLogger("com.r3.corda.networkmanage.hsm.generator.Main")
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
run(parseParameters(parseCommandLine(*args)))
|
run(parseParameters(ConfigFilePathArgsParser().parseOrExit(*args)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun run(parameters: GeneratorParameters) {
|
fun run(parameters: GeneratorParameters) {
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.r3.corda.networkmanage.tools.crr.submission
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.utils.ArgsParser
|
||||||
|
import joptsimple.OptionSet
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
class CRRToolArgsParser : ArgsParser<URL>() {
|
||||||
|
private val submissionUrlArg = optionParser
|
||||||
|
.accepts("submission-url", "CRR submission endpoint.")
|
||||||
|
.withRequiredArg()
|
||||||
|
.required()
|
||||||
|
|
||||||
|
override fun parse(optionSet: OptionSet): URL {
|
||||||
|
return URL(optionSet.valueOf(submissionUrlArg))
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
package com.r3.corda.networkmanage.tools.crr.submission
|
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
|
||||||
import joptsimple.OptionParser
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
fun parseSubmissionUrl(vararg args: String): URL {
|
|
||||||
val optionParser = OptionParser()
|
|
||||||
val submissionUrlArg = optionParser
|
|
||||||
.accepts("submission-url", "CRR submission endpoint.")
|
|
||||||
.withRequiredArg()
|
|
||||||
.required()
|
|
||||||
val helpOption = optionParser.acceptsAll(listOf("h", "help"), "show help").forHelp()
|
|
||||||
|
|
||||||
val optionSet = optionParser.parse(*args)
|
|
||||||
// Print help and exit on help option or if there are missing options.
|
|
||||||
if (optionSet.has(helpOption) || !optionSet.has(submissionUrlArg)) {
|
|
||||||
throw ShowHelpException(optionParser)
|
|
||||||
}
|
|
||||||
return URL(optionSet.valueOf(submissionUrlArg))
|
|
||||||
}
|
|
@ -17,7 +17,7 @@ private val logger = LogManager.getLogger("com.r3.corda.networkmanage.common.too
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
initialiseSerialization()
|
initialiseSerialization()
|
||||||
try {
|
try {
|
||||||
submit(parseSubmissionUrl(*args))
|
submit(CRRToolArgsParser().parseOrExit(*args))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.error("Error when submitting a certificate revocation request.", e)
|
logger.error("Error when submitting a certificate revocation request.", e)
|
||||||
throw e
|
throw e
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.dev
|
package com.r3.corda.networkmanage.dev
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.configuration.parseCommandLine
|
import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser
|
||||||
import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_FILE
|
import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_FILE
|
||||||
import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS
|
import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS
|
||||||
import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_FILE
|
import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_FILE
|
||||||
@ -31,7 +31,7 @@ class GeneratorConfigurationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `config file is parsed correctly`() {
|
fun `config file is parsed correctly`() {
|
||||||
val config = parseParameters(parseCommandLine("--config-file", configPath))
|
val config = parseParameters(ConfigFilePathArgsParser().parseOrExit("--config-file", configPath))
|
||||||
assertEquals(GeneratorConfiguration.DEFAULT_DIRECTORY, config.directory)
|
assertEquals(GeneratorConfiguration.DEFAULT_DIRECTORY, config.directory)
|
||||||
assertEquals(DEV_CA_KEY_STORE_FILE, config.keyStoreFileName)
|
assertEquals(DEV_CA_KEY_STORE_FILE, config.keyStoreFileName)
|
||||||
assertEquals(DEV_CA_KEY_STORE_PASS, config.keyStorePass)
|
assertEquals(DEV_CA_KEY_STORE_PASS, config.keyStorePass)
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.doorman
|
package com.r3.corda.networkmanage.doorman
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
|
||||||
import joptsimple.OptionException
|
import joptsimple.OptionException
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -26,39 +25,32 @@ class DoormanArgsParserTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `should fail when network parameters file is missing`() {
|
fun `should fail when network parameters file is missing`() {
|
||||||
assertThatThrownBy {
|
assertThatThrownBy {
|
||||||
argsParser.parse("--config-file", validConfigPath, "--set-network-parameters", "not-here")
|
argsParser.parseOrExit("--config-file", validConfigPath, "--set-network-parameters", "not-here")
|
||||||
}.hasMessageContaining("not-here")
|
}.hasMessageContaining("not-here")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should fail when config file is missing`() {
|
fun `should fail when config file is missing`() {
|
||||||
assertThatThrownBy {
|
assertThatThrownBy {
|
||||||
argsParser.parse("--config-file", "not-existing-file")
|
argsParser.parseOrExit("--config-file", "not-existing-file")
|
||||||
}.hasMessageContaining("not-existing-file")
|
}.hasMessageContaining("not-existing-file")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should throw ShowHelpException when help option is passed on the command line`() {
|
|
||||||
assertFailsWith<ShowHelpException> {
|
|
||||||
argsParser.parse("-h")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should parse trust store password correctly`() {
|
fun `should parse trust store password correctly`() {
|
||||||
val parameter = argsParser.parse("--config-file", validConfigPath, "--mode", "ROOT_KEYGEN", "--trust-store-password", "testPassword")
|
val parameter = argsParser.parseOrExit("--config-file", validConfigPath, "--mode", "ROOT_KEYGEN", "--trust-store-password", "testPassword")
|
||||||
assertEquals("testPassword", parameter.trustStorePassword)
|
assertEquals("testPassword", parameter.trustStorePassword)
|
||||||
|
|
||||||
assertFailsWith<OptionException> {
|
assertFailsWith<OptionException> {
|
||||||
argsParser.parse("--trust-store-password")
|
argsParser.parseOrExit("--trust-store-password", printHelpOn = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should fail if password is provided in mode other then root keygen.
|
// Should fail if password is provided in mode other then root keygen.
|
||||||
assertFailsWith<IllegalArgumentException> {
|
assertFailsWith<IllegalArgumentException> {
|
||||||
argsParser.parse("--config-file", validConfigPath, "--trust-store-password", "testPassword")
|
argsParser.parseOrExit("--config-file", validConfigPath, "--trust-store-password", "testPassword")
|
||||||
}
|
}
|
||||||
|
|
||||||
// trust store password is optional.
|
// trust store password is optional.
|
||||||
assertNull(argsParser.parse("--config-file", validConfigPath).trustStorePassword)
|
assertNull(argsParser.parseOrExit("--config-file", validConfigPath).trustStorePassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ class SigningServiceArgsParserTest : TestBase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `doorman-based config file is parsed correctly`() {
|
fun `doorman-based config file is parsed correctly`() {
|
||||||
val cmdLineOptions = argsParser.parse("--config-file", doormanConfigPath)
|
val cmdLineOptions = argsParser.parseOrExit("--config-file", doormanConfigPath)
|
||||||
val config = parseConfig<SigningServiceConfig>(cmdLineOptions.configFile)
|
val config = parseConfig<SigningServiceConfig>(cmdLineOptions.configFile)
|
||||||
assertEquals("3001@192.168.0.1", config.device)
|
assertEquals("3001@192.168.0.1", config.device)
|
||||||
val doormanCertParameters = config.doorman!!
|
val doormanCertParameters = config.doorman!!
|
||||||
@ -37,7 +37,7 @@ class SigningServiceArgsParserTest : TestBase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `networkmap-based config file is parsed correctly`() {
|
fun `networkmap-based config file is parsed correctly`() {
|
||||||
val cmdLineOptions = argsParser.parse("--config-file", networkMapConfigPath)
|
val cmdLineOptions = argsParser.parseOrExit("--config-file", networkMapConfigPath)
|
||||||
val config = parseConfig<SigningServiceConfig>(cmdLineOptions.configFile)
|
val config = parseConfig<SigningServiceConfig>(cmdLineOptions.configFile)
|
||||||
assertEquals("3001@192.168.0.1", config.device)
|
assertEquals("3001@192.168.0.1", config.device)
|
||||||
val networkMapConfig = config.networkMap!!
|
val networkMapConfig = config.networkMap!!
|
||||||
@ -51,7 +51,7 @@ class SigningServiceArgsParserTest : TestBase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `should fail when config file is missing`() {
|
fun `should fail when config file is missing`() {
|
||||||
assertThatThrownBy {
|
assertThatThrownBy {
|
||||||
argsParser.parse("--config-file", "not-existing-file")
|
argsParser.parseOrExit("--config-file", "not-existing-file")
|
||||||
}.hasMessageContaining("not-existing-file")
|
}.hasMessageContaining("not-existing-file")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,7 @@
|
|||||||
|
|
||||||
package com.r3.corda.networkmanage.hsm.generator
|
package com.r3.corda.networkmanage.hsm.generator
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.configuration.parseCommandLine
|
import com.r3.corda.networkmanage.common.configuration.ConfigFilePathArgsParser
|
||||||
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
|
||||||
import com.typesafe.config.ConfigException
|
import com.typesafe.config.ConfigException
|
||||||
import joptsimple.OptionException
|
import joptsimple.OptionException
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
@ -31,22 +30,15 @@ class GeneratorParametersTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `should fail when config file is missing`() {
|
fun `should fail when config file is missing`() {
|
||||||
val message = assertFailsWith<OptionException> {
|
val message = assertFailsWith<OptionException> {
|
||||||
parseCommandLine("--config-file", "not-existing-file")
|
ConfigFilePathArgsParser().parseOrExit("--config-file", "not-existing-file")
|
||||||
}.message
|
}.message
|
||||||
Assertions.assertThat(message).contains("not-existing-file")
|
Assertions.assertThat(message).contains("not-existing-file")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should throw ShowHelpException when help option is passed on the command line`() {
|
|
||||||
assertFailsWith<ShowHelpException> {
|
|
||||||
parseCommandLine("-h")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should fail when config is invalid`() {
|
fun `should fail when config is invalid`() {
|
||||||
assertFailsWith<ConfigException.Missing> {
|
assertFailsWith<ConfigException.Missing> {
|
||||||
parseParameters(parseCommandLine("--config-file", invalidConfigPath))
|
parseParameters(ConfigFilePathArgsParser().parseOrExit("--config-file", invalidConfigPath))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,6 +63,6 @@ class GeneratorParametersTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseCommandLineAndGetParameters(): GeneratorParameters {
|
private fun parseCommandLineAndGetParameters(): GeneratorParameters {
|
||||||
return parseParameters(parseCommandLine(*validArgs))
|
return parseParameters(ConfigFilePathArgsParser().parseOrExit(*validArgs))
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user