mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
some refactoring and more comments.
This commit is contained in:
parent
011dee09d8
commit
b651074523
@ -4,6 +4,7 @@ import com.google.common.net.HostAndPort
|
|||||||
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
|
||||||
|
import net.corda.core.createDirectories
|
||||||
import net.corda.core.crypto.X509Utilities
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.X509Utilities.CACertAndKey
|
import net.corda.core.crypto.X509Utilities.CACertAndKey
|
||||||
import net.corda.core.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
|
import net.corda.core.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
|
||||||
@ -42,16 +43,14 @@ import kotlin.concurrent.thread
|
|||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CertificateSigningServer runs on Jetty server and provide certificate signing service via http.
|
* DoormanServer runs on Jetty server and provide certificate signing service via http.
|
||||||
* 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]
|
||||||
*/
|
*/
|
||||||
class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, val rootCACert: Certificate, val storage: CertificationRequestStorage) : Closeable {
|
val logger = loggerFor<DoormanServer>()
|
||||||
companion object {
|
|
||||||
val log = loggerFor<DoormanServer>()
|
|
||||||
}
|
|
||||||
|
|
||||||
val server: Server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply {
|
class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, val rootCACert: Certificate, val storage: CertificationRequestStorage) : Closeable {
|
||||||
|
private val server: Server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply {
|
||||||
server.handler = HandlerCollection().apply {
|
server.handler = HandlerCollection().apply {
|
||||||
addHandler(buildServletContextHandler())
|
addHandler(buildServletContextHandler())
|
||||||
}
|
}
|
||||||
@ -64,15 +63,15 @@ class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey,
|
|||||||
.first()
|
.first()
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
log.info("Shutting down Doorman Web Services...")
|
logger.info("Shutting down Doorman Web Services...")
|
||||||
server.stop()
|
server.stop()
|
||||||
server.join()
|
server.join()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
log.info("Starting Doorman Web Services...")
|
logger.info("Starting Doorman Web Services...")
|
||||||
server.start()
|
server.start()
|
||||||
log.info("Doorman Web Services started on $hostAndPort")
|
logger.info("Doorman Web Services started on $hostAndPort")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildServletContextHandler(): ServletContextHandler {
|
private fun buildServletContextHandler(): ServletContextHandler {
|
||||||
@ -90,7 +89,7 @@ class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DoormanParameters(args: Array<String>) {
|
private 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()
|
||||||
@ -113,7 +112,7 @@ class DoormanParameters(args: Array<String>) {
|
|||||||
val caPrivateKeyPassword: String? by config.getOrElse { null }
|
val caPrivateKeyPassword: String? by config.getOrElse { null }
|
||||||
val rootKeystorePassword: String? by config.getOrElse { null }
|
val rootKeystorePassword: String? by config.getOrElse { null }
|
||||||
val rootPrivateKeyPassword: String? by config.getOrElse { null }
|
val rootPrivateKeyPassword: String? by config.getOrElse { null }
|
||||||
val approveAll: Boolean by config
|
val approveAll: Boolean by config.getOrElse { false }
|
||||||
val host: String by config
|
val host: String by config
|
||||||
val port: Int by config
|
val port: Int by config
|
||||||
val dataSourceProperties: Properties by config
|
val dataSourceProperties: Properties by config
|
||||||
@ -127,21 +126,25 @@ class DoormanParameters(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
/** Read password from console, do a readLine instead if console is null (e.g. when debugging in IDE). */
|
||||||
fun readPassword(fmt: String): String {
|
private 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))
|
||||||
} else {
|
} else {
|
||||||
print(fmt)
|
print(fmt)
|
||||||
readLine()!!
|
readLine()!!
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
DoormanParameters(args).run {
|
DoormanParameters(args).run {
|
||||||
val log = DoormanServer.log
|
|
||||||
when (mode) {
|
when (mode) {
|
||||||
DoormanParameters.Mode.ROOT_KEYGEN -> {
|
DoormanParameters.Mode.ROOT_KEYGEN -> {
|
||||||
println("Generating Root CA keypair and certificate.")
|
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 rootStore = loadOrCreateKeyStore(rootStorePath, rootKeystorePassword)
|
||||||
val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ")
|
val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ")
|
||||||
|
|
||||||
@ -160,7 +163,8 @@ fun main(args: Array<String>) {
|
|||||||
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 -> {
|
DoormanParameters.Mode.CA_KEYGEN -> {
|
||||||
println("Generating Intermediate CA keypair and certificate.")
|
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 rootKeystorePassword = rootKeystorePassword ?: readPassword("Root Keystore Password : ")
|
||||||
val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ")
|
val rootPrivateKeyPassword = rootPrivateKeyPassword ?: readPassword("Root Private Key Password : ")
|
||||||
val rootKeyStore = loadKeyStore(rootStorePath, rootKeystorePassword)
|
val rootKeyStore = loadKeyStore(rootStorePath, rootKeystorePassword)
|
||||||
@ -169,6 +173,8 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ")
|
val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ")
|
||||||
val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ")
|
val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ")
|
||||||
|
// Ensure folder exists.
|
||||||
|
keystorePath.parent.createDirectories()
|
||||||
val keyStore = loadOrCreateKeyStore(keystorePath, keystorePassword)
|
val keyStore = loadOrCreateKeyStore(keystorePath, keystorePassword)
|
||||||
|
|
||||||
if (keyStore.containsAlias(CORDA_INTERMEDIATE_CA_PRIVATE_KEY)) {
|
if (keyStore.containsAlias(CORDA_INTERMEDIATE_CA_PRIVATE_KEY)) {
|
||||||
@ -186,21 +192,20 @@ fun main(args: Array<String>) {
|
|||||||
println(loadKeyStore(keystorePath, keystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey)
|
println(loadKeyStore(keystorePath, keystorePassword).getCertificate(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).publicKey)
|
||||||
}
|
}
|
||||||
DoormanParameters.Mode.DOORMAN -> {
|
DoormanParameters.Mode.DOORMAN -> {
|
||||||
log.info("Starting certificate signing server.")
|
logger.info("Starting Doorman server.")
|
||||||
|
// Get password from console if not in config.
|
||||||
val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ")
|
val keystorePassword = keystorePassword ?: readPassword("Keystore Password : ")
|
||||||
val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ")
|
val caPrivateKeyPassword = caPrivateKeyPassword ?: readPassword("CA Private Key Password : ")
|
||||||
|
|
||||||
val keystore = X509Utilities.loadKeyStore(keystorePath, keystorePassword)
|
val keystore = X509Utilities.loadKeyStore(keystorePath, keystorePassword)
|
||||||
val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).last()
|
val rootCACert = keystore.getCertificateChain(CORDA_INTERMEDIATE_CA_PRIVATE_KEY).last()
|
||||||
val caCertAndKey = X509Utilities.loadCertificateAndKey(keystore, caPrivateKeyPassword, CORDA_INTERMEDIATE_CA_PRIVATE_KEY)
|
val caCertAndKey = X509Utilities.loadCertificateAndKey(keystore, caPrivateKeyPassword, CORDA_INTERMEDIATE_CA_PRIVATE_KEY)
|
||||||
|
|
||||||
// Create DB connection.
|
// Create DB connection.
|
||||||
val (datasource, database) = configureDatabase(dataSourceProperties)
|
val (datasource, database) = configureDatabase(dataSourceProperties)
|
||||||
val storage = DBCertificateRequestStorage(database)
|
val storage = DBCertificateRequestStorage(database)
|
||||||
// Daemon thread approving all request periodically.
|
// Daemon thread approving all request periodically.
|
||||||
val approvalThread = if (approveAll) {
|
if (approveAll) {
|
||||||
thread(name = "Request Approval Daemon") {
|
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) {
|
while (true) {
|
||||||
sleep(10.seconds.toMillis())
|
sleep(10.seconds.toMillis())
|
||||||
for (id in storage.getPendingRequestIds()) {
|
for (id in storage.getPendingRequestIds()) {
|
||||||
@ -210,18 +215,15 @@ fun main(args: Array<String>) {
|
|||||||
if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName), listOf(it.ipAddress))
|
if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName), listOf(it.ipAddress))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
log.info("Approved $id")
|
logger.info("Approved request $id")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else null
|
|
||||||
DoormanServer(HostAndPort.fromParts(host, port), caCertAndKey, rootCACert, storage).use {
|
|
||||||
it.start()
|
|
||||||
it.server.join()
|
|
||||||
approvalThread?.interrupt()
|
|
||||||
approvalThread?.join()
|
|
||||||
}
|
}
|
||||||
|
val doorman = DoormanServer(HostAndPort.fromParts(host, port), caCertAndKey, rootCACert, storage)
|
||||||
|
doorman.start()
|
||||||
|
Runtime.getRuntime().addShutdownHook(thread(start = false) { doorman.close() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,21 @@ import joptsimple.ArgumentAcceptingOptionSpec
|
|||||||
import joptsimple.OptionParser
|
import joptsimple.OptionParser
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert commandline arguments to [Config] object will allow us to use kotlin delegate with [ConfigHelper].
|
||||||
|
*/
|
||||||
object OptionParserHelper {
|
object OptionParserHelper {
|
||||||
fun Array<String>.toConfigWithOptions(options: OptionParser.() -> Unit): Config {
|
fun Array<String>.toConfigWithOptions(registerOptions: OptionParser.() -> Unit): Config {
|
||||||
val parser = OptionParser()
|
val parser = OptionParser()
|
||||||
val helpOption = parser.acceptsAll(listOf("h", "?", "help"), "show help").forHelp();
|
val helpOption = parser.acceptsAll(listOf("h", "?", "help"), "show help").forHelp();
|
||||||
options(parser)
|
registerOptions(parser)
|
||||||
val optionSet = parser.parse(*this)
|
val optionSet = parser.parse(*this)
|
||||||
|
// Print help and exit on help option.
|
||||||
if (optionSet.has(helpOption)) {
|
if (optionSet.has(helpOption)) {
|
||||||
parser.printHelpOn(System.out)
|
parser.printHelpOn(System.out)
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
// Convert all command line options to Config.
|
||||||
return ConfigFactory.parseMap(parser.recognizedOptions().mapValues {
|
return ConfigFactory.parseMap(parser.recognizedOptions().mapValues {
|
||||||
val optionSpec = it.value
|
val optionSpec = it.value
|
||||||
if (optionSpec is ArgumentAcceptingOptionSpec<*> && !optionSpec.requiresArgument() && optionSet.has(optionSpec)) true else optionSpec.value(optionSet)
|
if (optionSpec is ArgumentAcceptingOptionSpec<*> && !optionSpec.requiresArgument() && optionSet.has(optionSpec)) true else optionSpec.value(optionSet)
|
||||||
|
Loading…
Reference in New Issue
Block a user