From 94bc130721e5eb0dcd8e5815ac87aa0bd8d4c974 Mon Sep 17 00:00:00 2001 From: Patrick Kuo Date: Fri, 10 Feb 2017 10:28:27 +0000 Subject: [PATCH] Addressed PR issues --- .../main/kotlin/com/r3/corda/doorman/Main.kt | 170 +++++++++--------- .../r3/corda/doorman/DoormanParametersTest.kt | 2 - 2 files changed, 90 insertions(+), 82 deletions(-) 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 c65ff09ce0..83ab2337cf 100644 --- a/doorman/src/main/kotlin/com/r3/corda/doorman/Main.kt +++ b/doorman/src/main/kotlin/com/r3/corda/doorman/Main.kt @@ -1,6 +1,7 @@ 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 @@ -47,9 +48,12 @@ import kotlin.system.exitProcess * The server will require keystorePath, keystore password and key password via command line input. * The Intermediate CA certificate,Intermediate CA private key and Root CA Certificate should use alias name specified in [X509Utilities] */ -val logger = loggerFor() class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, val rootCACert: Certificate, val storage: CertificationRequestStorage) : Closeable { + companion object { + val logger = loggerFor() + } + private val server: Server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply { server.handler = HandlerCollection().apply { addHandler(buildServletContextHandler()) @@ -89,7 +93,7 @@ class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, } } -private class DoormanParameters(args: Array) { +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() @@ -136,94 +140,100 @@ private fun readPassword(fmt: String): String { } } -fun main(args: Array) { - DoormanParameters(args).run { - when (mode) { - DoormanParameters.Mode.ROOT_KEYGEN -> { - println("Generating Root CA keypair and certificate.") - // Get password from console if not in config. - 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 : ") +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 : ") + // Ensure folder exists. + rootStorePath.parent.createDirectories() + val rootStore = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword) + 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 - println("Key $CORDA_ROOT_CA_PRIVATE_KEY already exists in keystore, process will now terminate.") - println(oldKey) - exitProcess(1) - } + if (rootStore.containsAlias(CORDA_ROOT_CA_PRIVATE_KEY)) { + val oldKey = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword).getCertificate(CORDA_ROOT_CA_PRIVATE_KEY).publicKey + println("Key $CORDA_ROOT_CA_PRIVATE_KEY already exists in keystore, process will now terminate.") + println(oldKey) + exitProcess(1) + } - val selfSignCert = X509Utilities.createSelfSignedCACert(CORDA_ROOT_CA) - rootStore.addOrReplaceKey(CORDA_ROOT_CA_PRIVATE_KEY, selfSignCert.keyPair.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert.certificate)) - saveKeyStore(rootStore, rootStorePath, rootKeystorePassword) + val selfSignCert = X509Utilities.createSelfSignedCACert(CORDA_ROOT_CA) + rootStore.addOrReplaceKey(CORDA_ROOT_CA_PRIVATE_KEY, selfSignCert.keyPair.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert.certificate)) + saveKeyStore(rootStore, rootStorePath, rootKeystorePassword) - println("Root CA keypair and certificate stored in $rootStorePath.") - println(loadKeyStore(rootStorePath, rootKeystorePassword).getCertificate(CORDA_ROOT_CA_PRIVATE_KEY).publicKey) - } - DoormanParameters.Mode.CA_KEYGEN -> { - 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 rootKeyStore = loadKeyStore(rootStorePath, rootKeystorePassword) + println("Root CA keypair and certificate stored in $rootStorePath.") + println(loadKeyStore(rootStorePath, rootKeystorePassword).getCertificate(CORDA_ROOT_CA_PRIVATE_KEY).publicKey) +} - val rootKeyAndCert = loadCertificateAndKey(rootKeyStore, rootPrivateKeyPassword, CORDA_ROOT_CA_PRIVATE_KEY) +private fun DoormanParameters.generateKeyPair() { + 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 rootKeyStore = loadKeyStore(rootStorePath, rootKeystorePassword) - 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) + val rootKeyAndCert = loadCertificateAndKey(rootKeyStore, rootPrivateKeyPassword, CORDA_ROOT_CA_PRIVATE_KEY) - if (keyStore.containsAlias(CORDA_INTERMEDIATE_CA_PRIVATE_KEY)) { - val oldKey = loadOrCreateKeyStore(keystorePath, rootKeystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey - println("Key $CORDA_INTERMEDIATE_CA_PRIVATE_KEY already exists in keystore, process will now terminate.") - println(oldKey) - exitProcess(1) - } + 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) - val intermediateKeyAndCert = createIntermediateCert(CORDA_INTERMEDIATE_CA, rootKeyAndCert) - keyStore.addOrReplaceKey(CORDA_INTERMEDIATE_CA_PRIVATE_KEY, intermediateKeyAndCert.keyPair.private, - caPrivateKeyPassword.toCharArray(), arrayOf(intermediateKeyAndCert.certificate, rootKeyAndCert.certificate)) - saveKeyStore(keyStore, keystorePath, keystorePassword) - println("Intermediate CA keypair and certificate stored in $keystorePath.") - println(loadKeyStore(keystorePath, keystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey) - } - DoormanParameters.Mode.DOORMAN -> { - 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 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) - // Create DB connection. - val (datasource, database) = configureDatabase(dataSourceProperties) - val storage = DBCertificateRequestStorage(database) - // Daemon thread approving all request periodically. - if (approveAll) { - thread(name = "Request Approval Daemon", isDaemon = true) { - logger.warn("Doorman server is in 'Approve All' mode, this will approve all incoming certificate signing request.") - while (true) { - sleep(10.seconds.toMillis()) - for (id in storage.getPendingRequestIds()) { - storage.approveRequest(id, { - JcaPKCS10CertificationRequest(it.request).run { - X509Utilities.createServerCert(subject, publicKey, caCertAndKey, - if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName), listOf(it.ipAddress)) - } - }) - logger.info("Approved request $id") - } + if (keyStore.containsAlias(CORDA_INTERMEDIATE_CA_PRIVATE_KEY)) { + val oldKey = loadOrCreateKeyStore(keystorePath, rootKeystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey + println("Key $CORDA_INTERMEDIATE_CA_PRIVATE_KEY already exists in keystore, process will now terminate.") + println(oldKey) + exitProcess(1) + } + + val intermediateKeyAndCert = createIntermediateCert(CORDA_INTERMEDIATE_CA, rootKeyAndCert) + keyStore.addOrReplaceKey(CORDA_INTERMEDIATE_CA_PRIVATE_KEY, intermediateKeyAndCert.keyPair.private, + caPrivateKeyPassword.toCharArray(), arrayOf(intermediateKeyAndCert.certificate, rootKeyAndCert.certificate)) + saveKeyStore(keyStore, keystorePath, keystorePassword) + println("Intermediate CA keypair and certificate stored in $keystorePath.") + println(loadKeyStore(keystorePath, keystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey) +} + +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 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) + // Create DB connection. + val (datasource, database) = configureDatabase(dataSourceProperties) + val storage = DBCertificateRequestStorage(database) + // Daemon thread approving all request periodically. + if (approveAll) { + thread(name = "Request Approval Daemon", isDaemon = true) { + logger.warn("Doorman server is in 'Approve All' mode, this will approve all incoming certificate signing request.") + while (true) { + sleep(10.seconds.toMillis()) + for (id in storage.getPendingRequestIds()) { + storage.approveRequest(id, { + JcaPKCS10CertificationRequest(it.request).run { + X509Utilities.createServerCert(subject, publicKey, caCertAndKey, + if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName), listOf(it.ipAddress)) } - } + }) + logger.info("Approved request $id") } - val doorman = DoormanServer(HostAndPort.fromParts(host, port), caCertAndKey, rootCACert, storage) - doorman.start() - Runtime.getRuntime().addShutdownHook(thread(start = false) { doorman.close() }) } } } + val doorman = DoormanServer(HostAndPort.fromParts(host, port), caCertAndKey, rootCACert, storage) + doorman.start() + Runtime.getRuntime().addShutdownHook(thread(start = false) { doorman.close() }) +} + +fun main(args: Array) { + DoormanParameters(args).run { + when (mode) { + DoormanParameters.Mode.ROOT_KEYGEN -> generateRootKeyPair() + DoormanParameters.Mode.CA_KEYGEN -> generateKeyPair() + DoormanParameters.Mode.DOORMAN -> startDoorman() + } + } } diff --git a/doorman/src/test/kotlin/com/r3/corda/doorman/DoormanParametersTest.kt b/doorman/src/test/kotlin/com/r3/corda/doorman/DoormanParametersTest.kt index 40fb2f3cfc..7767d010c0 100644 --- a/doorman/src/test/kotlin/com/r3/corda/doorman/DoormanParametersTest.kt +++ b/doorman/src/test/kotlin/com/r3/corda/doorman/DoormanParametersTest.kt @@ -19,5 +19,3 @@ class DoormanParametersTest { assertEquals(1000, params2.port) } } - -