From 1e8c80855cca6a05467a42ab80a303029abe3bac Mon Sep 17 00:00:00 2001 From: Patrick Kuo Date: Mon, 13 Feb 2017 15:00:57 +0000 Subject: [PATCH] * Moved DoormanParameter to its own file * throws ShowHelpException instead of exitProcess in the helper method. --- .../com/r3/corda/doorman/DoormanParameters.kt | 49 ++++++++++++ .../main/kotlin/com/r3/corda/doorman/Main.kt | 80 +++++-------------- .../r3/corda/doorman/OptionParserUtilities.kt | 8 +- 3 files changed, 73 insertions(+), 64 deletions(-) create mode 100644 doorman/src/main/kotlin/com/r3/corda/doorman/DoormanParameters.kt diff --git a/doorman/src/main/kotlin/com/r3/corda/doorman/DoormanParameters.kt b/doorman/src/main/kotlin/com/r3/corda/doorman/DoormanParameters.kt new file mode 100644 index 0000000000..adee96471f --- /dev/null +++ b/doorman/src/main/kotlin/com/r3/corda/doorman/DoormanParameters.kt @@ -0,0 +1,49 @@ +package com.r3.corda.doorman + +import com.r3.corda.doorman.OptionParserHelper.toConfigWithOptions +import net.corda.core.div +import net.corda.node.services.config.ConfigHelper +import net.corda.node.services.config.getOrElse +import net.corda.node.services.config.getValue +import java.nio.file.Path +import java.nio.file.Paths +import java.util.* + +class DoormanParameters(args: Array) { + private val argConfig = args.toConfigWithOptions { + accepts("basedir", "Overriding configuration filepath, default to current directory.").withRequiredArg().describedAs("filepath") + accepts("keygen", "Generate CA keypair and certificate using provide Root CA key.").withOptionalArg() + accepts("rootKeygen", "Generate Root CA keypair and certificate.").withOptionalArg() + accepts("approveAll", "Approve all certificate signing request.").withOptionalArg() + accepts("keystorePath", "CA keystore filepath, default to [basedir]/certificates/caKeystore.jks.").withRequiredArg().describedAs("filepath") + accepts("rootStorePath", "Root CA keystore filepath, default to [basedir]/certificates/rootCAKeystore.jks.").withRequiredArg().describedAs("filepath") + accepts("keystorePassword", "CA keystore password.").withRequiredArg().describedAs("password") + accepts("caPrivateKeyPassword", "CA private key password.").withRequiredArg().describedAs("password") + accepts("rootKeystorePassword", "Root CA keystore password.").withRequiredArg().describedAs("password") + accepts("rootPrivateKeyPassword", "Root private key password.").withRequiredArg().describedAs("password") + accepts("host", "Doorman web service host override").withRequiredArg().describedAs("hostname") + accepts("port", "Doorman web service port override").withRequiredArg().ofType(Int::class.java).describedAs("port number") + } + private val basedir by argConfig.getOrElse { Paths.get(".") } + private val config = argConfig.withFallback(ConfigHelper.loadConfig(basedir, allowMissingConfig = true)) + val keystorePath: Path by config.getOrElse { basedir / "certificates" / "caKeystore.jks" } + val rootStorePath: Path by config.getOrElse { basedir / "certificates" / "rootCAKeystore.jks" } + val keystorePassword: String? by config.getOrElse { null } + val caPrivateKeyPassword: String? by config.getOrElse { null } + val rootKeystorePassword: String? by config.getOrElse { null } + val rootPrivateKeyPassword: String? by config.getOrElse { null } + val approveAll: Boolean by config.getOrElse { false } + val host: String by config + val port: Int by config + val dataSourceProperties: Properties by config + private val keygen: Boolean by config.getOrElse { false } + private val rootKeygen: Boolean by config.getOrElse { false } + + val mode = if (rootKeygen) Mode.ROOT_KEYGEN else if (keygen) Mode.CA_KEYGEN else Mode.DOORMAN + + enum class Mode { + DOORMAN, CA_KEYGEN, ROOT_KEYGEN + } +} + + diff --git a/doorman/src/main/kotlin/com/r3/corda/doorman/Main.kt b/doorman/src/main/kotlin/com/r3/corda/doorman/Main.kt index 83ab2337cf..bd51d30a75 100644 --- a/doorman/src/main/kotlin/com/r3/corda/doorman/Main.kt +++ b/doorman/src/main/kotlin/com/r3/corda/doorman/Main.kt @@ -2,7 +2,6 @@ package com.r3.corda.doorman import com.google.common.net.HostAndPort import com.r3.corda.doorman.DoormanServer.Companion.logger -import com.r3.corda.doorman.OptionParserHelper.toConfigWithOptions import com.r3.corda.doorman.persistence.CertificationRequestStorage import com.r3.corda.doorman.persistence.DBCertificateRequestStorage import net.corda.core.createDirectories @@ -18,12 +17,8 @@ import net.corda.core.crypto.X509Utilities.loadCertificateAndKey import net.corda.core.crypto.X509Utilities.loadKeyStore import net.corda.core.crypto.X509Utilities.loadOrCreateKeyStore import net.corda.core.crypto.X509Utilities.saveKeyStore -import net.corda.core.div import net.corda.core.seconds import net.corda.core.utilities.loggerFor -import net.corda.node.services.config.ConfigHelper -import net.corda.node.services.config.getOrElse -import net.corda.node.services.config.getValue import net.corda.node.utilities.configureDatabase import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest import org.eclipse.jetty.server.Server @@ -36,10 +31,7 @@ import org.glassfish.jersey.servlet.ServletContainer import java.io.Closeable import java.lang.Thread.sleep import java.net.InetSocketAddress -import java.nio.file.Path -import java.nio.file.Paths import java.security.cert.Certificate -import java.util.* import kotlin.concurrent.thread import kotlin.system.exitProcess @@ -55,7 +47,7 @@ class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, } private val server: Server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply { - server.handler = HandlerCollection().apply { + handler = HandlerCollection().apply { addHandler(buildServletContextHandler()) } } @@ -93,43 +85,6 @@ class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, } } -class DoormanParameters(args: Array) { - private val argConfig = args.toConfigWithOptions { - accepts("basedir", "Overriding configuration filepath, default to current directory.").withRequiredArg().describedAs("filepath") - accepts("keygen", "Generate CA keypair and certificate using provide Root CA key.").withOptionalArg() - accepts("rootKeygen", "Generate Root CA keypair and certificate.").withOptionalArg() - accepts("approveAll", "Approve all certificate signing request.").withOptionalArg() - accepts("keystorePath", "CA keystore filepath, default to [basedir]/certificates/caKeystore.jks.").withRequiredArg().describedAs("filepath") - accepts("rootStorePath", "Root CA keystore filepath, default to [basedir]/certificates/rootCAKeystore.jks.").withRequiredArg().describedAs("filepath") - accepts("keystorePassword", "CA keystore password.").withRequiredArg().describedAs("password") - accepts("caPrivateKeyPassword", "CA private key password.").withRequiredArg().describedAs("password") - accepts("rootKeystorePassword", "Root CA keystore password.").withRequiredArg().describedAs("password") - accepts("rootPrivateKeyPassword", "Root private key password.").withRequiredArg().describedAs("password") - accepts("host", "Doorman web service host override").withRequiredArg().describedAs("hostname") - accepts("port", "Doorman web service port override").withRequiredArg().ofType(Int::class.java).describedAs("port number") - } - private val basedir by argConfig.getOrElse { Paths.get(".") } - private val config = argConfig.withFallback(ConfigHelper.loadConfig(basedir, allowMissingConfig = true)) - val keystorePath: Path by config.getOrElse { basedir / "certificates" / "caKeystore.jks" } - val rootStorePath: Path by config.getOrElse { basedir / "certificates" / "rootCAKeystore.jks" } - val keystorePassword: String? by config.getOrElse { null } - val caPrivateKeyPassword: String? by config.getOrElse { null } - val rootKeystorePassword: String? by config.getOrElse { null } - val rootPrivateKeyPassword: String? by config.getOrElse { null } - val approveAll: Boolean by config.getOrElse { false } - val host: String by config - val port: Int by config - val dataSourceProperties: Properties by config - private val keygen: Boolean by config.getOrElse { false } - private val rootKeygen: Boolean by config.getOrElse { false } - - val mode = if (rootKeygen) Mode.ROOT_KEYGEN else if (keygen) Mode.CA_KEYGEN else Mode.DOORMAN - - enum class Mode { - DOORMAN, CA_KEYGEN, ROOT_KEYGEN - } -} - /** Read password from console, do a readLine instead if console is null (e.g. when debugging in IDE). */ private fun readPassword(fmt: String): String { return if (System.console() != null) { @@ -143,11 +98,11 @@ private fun readPassword(fmt: String): String { private fun DoormanParameters.generateRootKeyPair() { println("Generating Root CA keypair and certificate.") // Get password from console if not in config. - val rootKeystorePassword = rootKeystorePassword ?: readPassword("Root Keystore Password : ") + val rootKeystorePassword = rootKeystorePassword ?: readPassword("Root Keystore Password: ") // Ensure folder exists. rootStorePath.parent.createDirectories() val rootStore = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword) - val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ") + val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password: ") if (rootStore.containsAlias(CORDA_ROOT_CA_PRIVATE_KEY)) { val oldKey = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword).getCertificate(CORDA_ROOT_CA_PRIVATE_KEY).publicKey @@ -164,17 +119,17 @@ private fun DoormanParameters.generateRootKeyPair() { println(loadKeyStore(rootStorePath, rootKeystorePassword).getCertificate(CORDA_ROOT_CA_PRIVATE_KEY).publicKey) } -private fun DoormanParameters.generateKeyPair() { +private fun DoormanParameters.generateCAKeyPair() { println("Generating Intermediate CA keypair and certificate using root keystore $rootStorePath.") // Get password from console if not in config. - val rootKeystorePassword = rootKeystorePassword ?: readPassword("Root Keystore Password : ") - val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ") + val rootKeystorePassword = rootKeystorePassword ?: readPassword("Root Keystore Password: ") + val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password: ") val rootKeyStore = loadKeyStore(rootStorePath, rootKeystorePassword) val rootKeyAndCert = loadCertificateAndKey(rootKeyStore, rootPrivateKeyPassword, CORDA_ROOT_CA_PRIVATE_KEY) - val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ") - val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ") + val keystorePassword = keystorePassword ?: readPassword("Keystore Password: ") + val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password: ") // Ensure folder exists. keystorePath.parent.createDirectories() val keyStore = loadOrCreateKeyStore(keystorePath, keystorePassword) @@ -197,8 +152,8 @@ private fun DoormanParameters.generateKeyPair() { private fun DoormanParameters.startDoorman() { logger.info("Starting Doorman server.") // Get password from console if not in config. - val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ") - val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ") + val keystorePassword = keystorePassword ?: readPassword("Keystore Password: ") + val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password: ") val keystore = X509Utilities.loadKeyStore(keystorePath, keystorePassword) val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).last() val caCertAndKey = X509Utilities.loadCertificateAndKey(keystore, caPrivateKeyPassword, CORDA_INTERMEDIATE_CA_PRIVATE_KEY) @@ -229,11 +184,16 @@ private fun DoormanParameters.startDoorman() { } fun main(args: Array) { - DoormanParameters(args).run { - when (mode) { - DoormanParameters.Mode.ROOT_KEYGEN -> generateRootKeyPair() - DoormanParameters.Mode.CA_KEYGEN -> generateKeyPair() - DoormanParameters.Mode.DOORMAN -> startDoorman() + try { + // TODO : Remove config overrides and solely use config file after testnet is finalized. + DoormanParameters(args).run { + when (mode) { + DoormanParameters.Mode.ROOT_KEYGEN -> generateRootKeyPair() + DoormanParameters.Mode.CA_KEYGEN -> generateCAKeyPair() + DoormanParameters.Mode.DOORMAN -> startDoorman() + } } + } catch (e: ShowHelpException) { + e.parser.printHelpOn(System.out) } } diff --git a/doorman/src/main/kotlin/com/r3/corda/doorman/OptionParserUtilities.kt b/doorman/src/main/kotlin/com/r3/corda/doorman/OptionParserUtilities.kt index b88c32dcdc..54847f9407 100644 --- a/doorman/src/main/kotlin/com/r3/corda/doorman/OptionParserUtilities.kt +++ b/doorman/src/main/kotlin/com/r3/corda/doorman/OptionParserUtilities.kt @@ -4,7 +4,6 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import joptsimple.ArgumentAcceptingOptionSpec import joptsimple.OptionParser -import kotlin.system.exitProcess /** * Convert commandline arguments to [Config] object will allow us to use kotlin delegate with [ConfigHelper]. @@ -17,8 +16,7 @@ object OptionParserHelper { val optionSet = parser.parse(*this) // Print help and exit on help option. if (optionSet.has(helpOption)) { - parser.printHelpOn(System.out) - exitProcess(0) + throw ShowHelpException(parser) } // Convert all command line options to Config. return ConfigFactory.parseMap(parser.recognizedOptions().mapValues { @@ -26,4 +24,6 @@ object OptionParserHelper { if (optionSpec is ArgumentAcceptingOptionSpec<*> && !optionSpec.requiresArgument() && optionSet.has(optionSpec)) true else optionSpec.value(optionSet) }.filterValues { it != null }) } -} \ No newline at end of file +} + +class ShowHelpException(val parser: OptionParser) : Exception()