Addressed PR issues

This commit is contained in:
Patrick Kuo 2017-02-10 10:28:27 +00:00
parent b651074523
commit 94bc130721
2 changed files with 90 additions and 82 deletions

View File

@ -1,6 +1,7 @@
package com.r3.corda.doorman package com.r3.corda.doorman
import com.google.common.net.HostAndPort 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.OptionParserHelper.toConfigWithOptions
import com.r3.corda.doorman.persistence.CertificationRequestStorage import com.r3.corda.doorman.persistence.CertificationRequestStorage
import com.r3.corda.doorman.persistence.DBCertificateRequestStorage 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 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] * The Intermediate CA certificate,Intermediate CA private key and Root CA Certificate should use alias name specified in [X509Utilities]
*/ */
val logger = loggerFor<DoormanServer>()
class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, val rootCACert: Certificate, val storage: CertificationRequestStorage) : Closeable { class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, val rootCACert: Certificate, val storage: CertificationRequestStorage) : Closeable {
companion object {
val logger = loggerFor<DoormanServer>()
}
private val server: Server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply { private val server: Server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply {
server.handler = HandlerCollection().apply { server.handler = HandlerCollection().apply {
addHandler(buildServletContextHandler()) addHandler(buildServletContextHandler())
@ -89,7 +93,7 @@ class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey,
} }
} }
private class DoormanParameters(args: Array<String>) { class DoormanParameters(args: Array<String>) {
private val argConfig = args.toConfigWithOptions { private val argConfig = args.toConfigWithOptions {
accepts("basedir", "Overriding configuration filepath, default to current directory.").withRequiredArg().describedAs("filepath") 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("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<String>) { private fun DoormanParameters.generateRootKeyPair() {
DoormanParameters(args).run { println("Generating Root CA keypair and certificate.")
when (mode) { // Get password from console if not in config.
DoormanParameters.Mode.ROOT_KEYGEN -> { val rootKeystorePassword = rootKeystorePassword ?: readPassword("Root Keystore Password : ")
println("Generating Root CA keypair and certificate.") // Ensure folder exists.
// Get password from console if not in config. rootStorePath.parent.createDirectories()
val rootKeystorePassword = rootKeystorePassword ?: readPassword("Root Keystore Password : ") val rootStore = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword)
// Ensure folder exists. val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ")
rootStorePath.parent.createDirectories()
val rootStore = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword)
val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ")
if (rootStore.containsAlias(CORDA_ROOT_CA_PRIVATE_KEY)) { if (rootStore.containsAlias(CORDA_ROOT_CA_PRIVATE_KEY)) {
val oldKey = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword).getCertificate(CORDA_ROOT_CA_PRIVATE_KEY).publicKey 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("Key $CORDA_ROOT_CA_PRIVATE_KEY already exists in keystore, process will now terminate.")
println(oldKey) println(oldKey)
exitProcess(1) exitProcess(1)
} }
val selfSignCert = X509Utilities.createSelfSignedCACert(CORDA_ROOT_CA) val selfSignCert = X509Utilities.createSelfSignedCACert(CORDA_ROOT_CA)
rootStore.addOrReplaceKey(CORDA_ROOT_CA_PRIVATE_KEY, selfSignCert.keyPair.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert.certificate)) rootStore.addOrReplaceKey(CORDA_ROOT_CA_PRIVATE_KEY, selfSignCert.keyPair.private, rootPrivateKeyPassword.toCharArray(), arrayOf(selfSignCert.certificate))
saveKeyStore(rootStore, rootStorePath, rootKeystorePassword) saveKeyStore(rootStore, rootStorePath, rootKeystorePassword)
println("Root CA keypair and certificate stored in $rootStorePath.") println("Root CA keypair and certificate stored in $rootStorePath.")
println(loadKeyStore(rootStorePath, rootKeystorePassword).getCertificate(CORDA_ROOT_CA_PRIVATE_KEY).publicKey) 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)
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 rootKeyAndCert = loadCertificateAndKey(rootKeyStore, rootPrivateKeyPassword, CORDA_ROOT_CA_PRIVATE_KEY)
val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ")
// Ensure folder exists.
keystorePath.parent.createDirectories()
val keyStore = loadOrCreateKeyStore(keystorePath, keystorePassword)
if (keyStore.containsAlias(CORDA_INTERMEDIATE_CA_PRIVATE_KEY)) { val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ")
val oldKey = loadOrCreateKeyStore(keystorePath, rootKeystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ")
println("Key $CORDA_INTERMEDIATE_CA_PRIVATE_KEY already exists in keystore, process will now terminate.") // Ensure folder exists.
println(oldKey) keystorePath.parent.createDirectories()
exitProcess(1) val keyStore = loadOrCreateKeyStore(keystorePath, keystorePassword)
}
val intermediateKeyAndCert = createIntermediateCert(CORDA_INTERMEDIATE_CA, rootKeyAndCert) if (keyStore.containsAlias(CORDA_INTERMEDIATE_CA_PRIVATE_KEY)) {
keyStore.addOrReplaceKey(CORDA_INTERMEDIATE_CA_PRIVATE_KEY, intermediateKeyAndCert.keyPair.private, val oldKey = loadOrCreateKeyStore(keystorePath, rootKeystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey
caPrivateKeyPassword.toCharArray(), arrayOf(intermediateKeyAndCert.certificate, rootKeyAndCert.certificate)) println("Key $CORDA_INTERMEDIATE_CA_PRIVATE_KEY already exists in keystore, process will now terminate.")
saveKeyStore(keyStore, keystorePath, keystorePassword) println(oldKey)
println("Intermediate CA keypair and certificate stored in $keystorePath.") exitProcess(1)
println(loadKeyStore(keystorePath, keystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey) }
}
DoormanParameters.Mode.DOORMAN -> { val intermediateKeyAndCert = createIntermediateCert(CORDA_INTERMEDIATE_CA, rootKeyAndCert)
logger.info("Starting Doorman server.") keyStore.addOrReplaceKey(CORDA_INTERMEDIATE_CA_PRIVATE_KEY, intermediateKeyAndCert.keyPair.private,
// Get password from console if not in config. caPrivateKeyPassword.toCharArray(), arrayOf(intermediateKeyAndCert.certificate, rootKeyAndCert.certificate))
val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ") saveKeyStore(keyStore, keystorePath, keystorePassword)
val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ") println("Intermediate CA keypair and certificate stored in $keystorePath.")
val keystore = X509Utilities.loadKeyStore(keystorePath, keystorePassword) println(loadKeyStore(keystorePath, keystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey)
val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).last() }
val caCertAndKey = X509Utilities.loadCertificateAndKey(keystore, caPrivateKeyPassword, CORDA_INTERMEDIATE_CA_PRIVATE_KEY)
// Create DB connection. private fun DoormanParameters.startDoorman() {
val (datasource, database) = configureDatabase(dataSourceProperties) logger.info("Starting Doorman server.")
val storage = DBCertificateRequestStorage(database) // Get password from console if not in config.
// Daemon thread approving all request periodically. val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ")
if (approveAll) { val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ")
thread(name = "Request Approval Daemon", isDaemon = true) { val keystore = X509Utilities.loadKeyStore(keystorePath, keystorePassword)
logger.warn("Doorman server is in 'Approve All' mode, this will approve all incoming certificate signing request.") val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).last()
while (true) { val caCertAndKey = X509Utilities.loadCertificateAndKey(keystore, caPrivateKeyPassword, CORDA_INTERMEDIATE_CA_PRIVATE_KEY)
sleep(10.seconds.toMillis()) // Create DB connection.
for (id in storage.getPendingRequestIds()) { val (datasource, database) = configureDatabase(dataSourceProperties)
storage.approveRequest(id, { val storage = DBCertificateRequestStorage(database)
JcaPKCS10CertificationRequest(it.request).run { // Daemon thread approving all request periodically.
X509Utilities.createServerCert(subject, publicKey, caCertAndKey, if (approveAll) {
if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName), listOf(it.ipAddress)) 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) {
logger.info("Approved request $id") 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<String>) {
DoormanParameters(args).run {
when (mode) {
DoormanParameters.Mode.ROOT_KEYGEN -> generateRootKeyPair()
DoormanParameters.Mode.CA_KEYGEN -> generateKeyPair()
DoormanParameters.Mode.DOORMAN -> startDoorman()
}
}
} }

View File

@ -19,5 +19,3 @@ class DoormanParametersTest {
assertEquals(1000, params2.port) assertEquals(1000, params2.port)
} }
} }