Merge branch 'master' into demobench

This commit is contained in:
Chris Rankin 2017-02-17 08:23:08 +00:00
commit ac56c7d451
11 changed files with 370 additions and 89 deletions

View File

@ -68,4 +68,11 @@ dependencies {
testCompile 'junit:junit:4.12'
testCompile "org.assertj:assertj-core:${assertj_version}"
testCompile "com.nhaarman:mockito-kotlin:0.6.1"
compile ('com.atlassian.jira:jira-rest-java-client-core:4.0.0'){
// The jira client includes jersey-core 1.5 which breaks everything.
exclude module: 'jersey-core'
}
// Needed by jira rest client
compile "com.atlassian.fugue:fugue:2.6.1"
}

View File

@ -0,0 +1,55 @@
package com.r3.corda.doorman
import com.r3.corda.doorman.OptionParserHelper.toConfigWithOptions
import com.typesafe.config.Config
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<String>) {
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("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 host: String by config
val port: Int by config
val dataSourceProperties: Properties by config
val jiraConfig = if (config.hasPath("jiraConfig")) JiraConfig(config.getConfig("jiraConfig")) else null
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
}
class JiraConfig(config: Config) {
val address: String by config
val projectCode: String by config
val username: String by config
val password: String by config
val doneTransitionCode: Int by config
}
}

View File

@ -1,14 +1,27 @@
package com.r3.corda.doorman
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory
import com.google.common.net.HostAndPort
import com.r3.corda.doorman.DoormanServer.Companion.logger
import com.r3.corda.doorman.persistence.CertificationRequestStorage
import com.r3.corda.doorman.persistence.DBCertificateRequestStorage
import joptsimple.ArgumentAcceptingOptionSpec
import joptsimple.OptionParser
import com.r3.corda.doorman.persistence.JiraCertificateRequestStorage
import net.corda.core.createDirectories
import net.corda.core.crypto.X509Utilities
import net.corda.core.utilities.debug
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_PRIVATE_KEY
import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA
import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA_PRIVATE_KEY
import net.corda.core.crypto.X509Utilities.addOrReplaceKey
import net.corda.core.crypto.X509Utilities.createIntermediateCert
import net.corda.core.crypto.X509Utilities.createServerCert
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.seconds
import net.corda.core.utilities.loggerFor
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.getProperties
import net.corda.node.utilities.configureDatabase
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import org.eclipse.jetty.server.Server
@ -19,22 +32,30 @@ import org.eclipse.jetty.servlet.ServletHolder
import org.glassfish.jersey.server.ResourceConfig
import org.glassfish.jersey.servlet.ServletContainer
import java.io.Closeable
import java.lang.Thread.sleep
import java.net.InetSocketAddress
import java.nio.file.Paths
import java.net.URI
import java.security.cert.Certificate
import kotlin.concurrent.thread
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 Intermediate CA certificate,Intermediate CA private key and Root CA Certificate should use alias name specified in [X509Utilities]
*/
class DoormanServer(val webServerAddr: HostAndPort, val doormanWebService: DoormanWebService) : Closeable {
class DoormanServer(webServerAddr: HostAndPort, val caCertAndKey: CACertAndKey, val rootCACert: Certificate, val storage: CertificationRequestStorage) : Closeable {
companion object {
val log = loggerFor<DoormanServer>()
val logger = loggerFor<DoormanServer>()
}
private val server: Server = Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply {
handler = HandlerCollection().apply {
addHandler(buildServletContextHandler())
}
}
private val server: Server = initWebServer()
val hostAndPort: HostAndPort get() = server.connectors
.map { it as? ServerConnector }
.filterNotNull()
@ -42,20 +63,15 @@ class DoormanServer(val webServerAddr: HostAndPort, val doormanWebService: Doorm
.first()
override fun close() {
log.info("Shutting down CertificateSigningService...")
logger.info("Shutting down Doorman Web Services...")
server.stop()
server.join()
}
private fun initWebServer(): Server {
return Server(InetSocketAddress(webServerAddr.hostText, webServerAddr.port)).apply {
log.info("Starting CertificateSigningService...")
handler = HandlerCollection().apply {
addHandler(buildServletContextHandler())
}
start()
log.info("CertificateSigningService started on $hostAndPort")
}
fun start() {
logger.info("Starting Doorman Web Services...")
server.start()
logger.info("Doorman Web Services started on $hostAndPort")
}
private fun buildServletContextHandler(): ServletContextHandler {
@ -63,7 +79,7 @@ class DoormanServer(val webServerAddr: HostAndPort, val doormanWebService: Doorm
contextPath = "/"
val resourceConfig = ResourceConfig().apply {
// Add your API provider classes (annotated for JAX-RS) here
register(doormanWebService)
register(DoormanWebService(caCertAndKey, rootCACert, storage))
}
val jerseyServlet = ServletHolder(ServletContainer(resourceConfig)).apply {
initOrder = 0 // Initialise at server start
@ -73,62 +89,126 @@ class DoormanServer(val webServerAddr: HostAndPort, val doormanWebService: Doorm
}
}
object ParamsSpec {
val parser = OptionParser()
val basedir: ArgumentAcceptingOptionSpec<String>? = parser.accepts("basedir", "Overriding configuration file path.")
.withRequiredArg()
/** 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) {
String(System.console().readPassword(fmt))
} else {
print(fmt)
readLine()!!
}
}
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)
}
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)
}
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 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: ")
// Ensure folder exists.
keystorePath.parent.createDirectories()
val keyStore = loadOrCreateKeyStore(keystorePath, keystorePassword)
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 requestStorage = DBCertificateRequestStorage(database)
val storage = if (jiraConfig == null) {
logger.warn("Doorman server is in 'Approve All' mode, this will approve all incoming certificate signing request.")
// Approve all pending request.
object : CertificationRequestStorage by requestStorage {
// The doorman is in approve all mode, returns all pending request id as approved request id.
override fun getApprovedRequestIds() = getPendingRequestIds()
}
} else {
val jiraClient = AsynchronousJiraRestClientFactory().createWithBasicHttpAuthentication(URI(jiraConfig.address), jiraConfig.username, jiraConfig.password)
JiraCertificateRequestStorage(requestStorage, jiraClient, jiraConfig.projectCode, jiraConfig.doneTransitionCode)
}
// Daemon thread approving request periodically.
thread(name = "Request Approval Daemon") {
while (true) {
sleep(10.seconds.toMillis())
// TODO: Handle rejected request?
for (id in storage.getApprovedRequestIds()) {
storage.approveRequest(id) {
val request = JcaPKCS10CertificationRequest(request)
createServerCert(request.subject, request.publicKey, caCertAndKey,
if (ipAddress == hostName) listOf() else listOf(hostName), listOf(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() })
}
fun main(args: Array<String>) {
val log = DoormanServer.log
log.info("Starting certificate signing server.")
try {
ParamsSpec.parser.parse(*args)
} catch (ex: Exception) {
log.error("Unable to parse args", ex)
ParamsSpec.parser.printHelpOn(System.out)
exitProcess(1)
}.run {
val basedir = Paths.get(valueOf(ParamsSpec.basedir) ?: ".")
val config = ConfigHelper.loadConfig(basedir)
val keystore = X509Utilities.loadKeyStore(Paths.get(config.getString("keystorePath")).normalize(), config.getString("keyStorePassword"))
val intermediateCACertAndKey = X509Utilities.loadCertificateAndKey(keystore, config.getString("caKeyPassword"), X509Utilities.CORDA_INTERMEDIATE_CA_PRIVATE_KEY)
val rootCA = keystore.getCertificateChain(X509Utilities.CORDA_INTERMEDIATE_CA_PRIVATE_KEY).last()
// Create DB connection.
val (datasource, database) = configureDatabase(config.getProperties("dataSourceProperties"))
val storage = DBCertificateRequestStorage(database)
val service = DoormanWebService(intermediateCACertAndKey, rootCA, storage)
// Background thread approving all request periodically.
var stopSigner = false
val certSinger = if (config.getBoolean("approveAll")) {
thread {
while (!stopSigner) {
Thread.sleep(1000)
for (id in storage.getPendingRequestIds()) {
storage.approveRequest(id, {
JcaPKCS10CertificationRequest(it.request).run {
X509Utilities.createServerCert(subject, publicKey, intermediateCACertAndKey,
if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName), listOf(it.ipAddress))
}
})
log.debug { "Approved $id" }
}
}
log.debug { "Certificate Signer thread stopped." }
// 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()
}
} else {
null
}
DoormanServer(HostAndPort.fromParts(config.getString("host"), config.getInt("port")), service).use {
Runtime.getRuntime().addShutdownHook(thread(false) {
stopSigner = true
certSinger?.join()
datasource.close()
})
}
} catch (e: ShowHelpException) {
e.parser.printHelpOn(System.out)
}
}

View File

@ -0,0 +1,29 @@
package com.r3.corda.doorman
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import joptsimple.ArgumentAcceptingOptionSpec
import joptsimple.OptionParser
/**
* Convert commandline arguments to [Config] object will allow us to use kotlin delegate with [ConfigHelper].
*/
object OptionParserHelper {
fun Array<String>.toConfigWithOptions(registerOptions: OptionParser.() -> Unit): Config {
val parser = OptionParser()
val helpOption = parser.acceptsAll(listOf("h", "?", "help"), "show help").forHelp();
registerOptions(parser)
val optionSet = parser.parse(*this)
// Print help and exit on help option.
if (optionSet.has(helpOption)) {
throw ShowHelpException(parser)
}
// Convert all command line options to Config.
return ConfigFactory.parseMap(parser.recognizedOptions().mapValues {
val optionSpec = it.value
if (optionSpec is ArgumentAcceptingOptionSpec<*> && !optionSpec.requiresArgument() && optionSet.has(optionSpec)) true else optionSpec.value(optionSet)
}.filterValues { it != null })
}
}
class ShowHelpException(val parser: OptionParser) : Exception()

View File

@ -26,7 +26,7 @@ interface CertificationRequestStorage {
/**
* Approve the given request by generating and storing a new certificate using the provided generator.
*/
fun approveRequest(requestId: String, certificateGenerator: (CertificationRequestData) -> Certificate)
fun approveRequest(requestId: String, generateCertificate: CertificationRequestData.() -> Certificate)
/**
* Reject the given request using the given reason.
@ -35,9 +35,13 @@ interface CertificationRequestStorage {
/**
* Retrieve list of request IDs waiting for approval.
* TODO : This is used for the background thread to approve request automatically without KYC checks, should be removed after testnet.
*/
fun getPendingRequestIds(): List<String>
/**
* Retrieve list of approved request IDs.
*/
fun getApprovedRequestIds(): List<String>
}
data class CertificationRequestData(val hostName: String, val ipAddress: String, val request: PKCS10CertificationRequest)

View File

@ -83,13 +83,13 @@ class DBCertificateRequestStorage(private val database: Database) : Certificatio
}
}
override fun approveRequest(requestId: String, certificateGenerator: (CertificationRequestData) -> Certificate) {
override fun approveRequest(requestId: String, generateCertificate: CertificationRequestData.() -> Certificate) {
databaseTransaction(database) {
val request = singleRequestWhere { DataTable.requestId eq requestId and DataTable.processTimestamp.isNull() }
if (request != null) {
withFinalizables { finalizables ->
DataTable.update({ DataTable.requestId eq requestId }) {
it[certificate] = serializeToBlob(certificateGenerator(request), finalizables)
it[certificate] = serializeToBlob(request.generateCertificate(), finalizables)
it[processTimestamp] = Instant.now()
}
}
@ -121,6 +121,8 @@ class DBCertificateRequestStorage(private val database: Database) : Certificatio
}
}
override fun getApprovedRequestIds(): List<String> = emptyList()
private fun singleRequestWhere(where: SqlExpressionBuilder.() -> Op<Boolean>): CertificationRequestData? {
return DataTable
.select(where)

View File

@ -0,0 +1,76 @@
package com.r3.corda.doorman.persistence
import com.atlassian.jira.rest.client.api.JiraRestClient
import com.atlassian.jira.rest.client.api.domain.Field
import com.atlassian.jira.rest.client.api.domain.IssueType
import com.atlassian.jira.rest.client.api.domain.input.IssueInputBuilder
import com.atlassian.jira.rest.client.api.domain.input.TransitionInput
import net.corda.core.crypto.X509Utilities
import net.corda.core.crypto.commonName
import net.corda.core.utilities.loggerFor
import org.bouncycastle.asn1.x500.style.BCStyle
import org.bouncycastle.openssl.jcajce.JcaPEMWriter
import org.bouncycastle.util.io.pem.PemObject
import java.io.StringWriter
import java.security.cert.Certificate
class JiraCertificateRequestStorage(val delegate: CertificationRequestStorage,
val jiraClient: JiraRestClient,
val projectCode: String,
val doneTransitionCode: Int) : CertificationRequestStorage by delegate {
private enum class Status {
Approved, Rejected
}
companion object {
private val logger = loggerFor<JiraCertificateRequestStorage>()
}
// The JIRA project must have a Request ID field and the Task issue type.
private val requestIdField: Field = jiraClient.metadataClient.fields.claim().find { it.name == "Request ID" }!!
private val taskIssueType: IssueType = jiraClient.metadataClient.issueTypes.claim().find { it.name == "Task" }!!
override fun saveRequest(certificationData: CertificationRequestData): String {
val requestId = delegate.saveRequest(certificationData)
// Make sure request has been accepted.
val response = getResponse(requestId)
if (response !is CertificateResponse.Unauthorised) {
val request = StringWriter()
JcaPEMWriter(request).use {
it.writeObject(PemObject("CERTIFICATE REQUEST", certificationData.request.encoded))
}
val commonName = certificationData.request.subject.commonName
val email = certificationData.request.subject.getRDNs(BCStyle.EmailAddress).firstOrNull()?.first?.value
val nearestCity = certificationData.request.subject.getRDNs(BCStyle.L).firstOrNull()?.first?.value
val issue = IssueInputBuilder().setIssueTypeId(taskIssueType.id)
.setProjectKey(projectCode)
.setDescription("Legal Name: $commonName\nNearest City: $nearestCity\nEmail: $email\n\n{code}$request{code}")
.setSummary(commonName)
.setFieldValue(requestIdField.id, requestId)
// This will block until the issue is created.
jiraClient.issueClient.createIssue(issue.build()).fail { logger.error("Exception when creating JIRA issue.", it) }.claim()
}
return requestId
}
override fun approveRequest(requestId: String, generateCertificate: CertificationRequestData.() -> Certificate) {
delegate.approveRequest(requestId, generateCertificate)
// Certificate should be created, retrieving it to attach to the jira task.
val certificate = (getResponse(requestId) as? CertificateResponse.Ready)?.certificate
// Jira only support ~ (contains) search for custom textfield.
val issue = jiraClient.searchClient.searchJql("'Request ID' ~ $requestId").claim().issues.firstOrNull()
if (issue != null) {
jiraClient.issueClient.transition(issue, TransitionInput(doneTransitionCode)).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
jiraClient.issueClient.addAttachment(issue.attachmentsUri, certificate?.encoded?.inputStream(), "${X509Utilities.CORDA_CLIENT_CA}.cer")
.fail { logger.error("Exception when uploading attachment to JIRA.", it) }.claim()
}
}
override fun getApprovedRequestIds(): List<String> = getRequestByStatus(Status.Approved)
private fun getRequestByStatus(status: Status): List<String> {
val issues = jiraClient.searchClient.searchJql("project = $projectCode AND status = $status").claim().issues
return issues.map { it.getField(requestIdField.id)?.value?.toString() }.filterNotNull()
}
}

View File

@ -1,9 +1,8 @@
host = localhost
port = 0
keystorePath = ${basedir}"/certificates/keystore.jks"
keyStorePassword = "password"
caKeyPassword = "password"
approveAll = true
keystorePath = ${basedir}"/certificates/caKeystore.jks"
keystorePassword = "password"
caPrivateKeyPassword = "password"
dataSourceProperties {
dataSourceClassName = org.h2.jdbcx.JdbcDataSource
@ -12,3 +11,11 @@ dataSourceProperties {
"dataSource.password" = ""
}
h2port = 0
jiraConfig{
address = "https://doorman-jira-host/"
projectCode = "TD"
username = "username"
password = "password"
doneTransitionCode = 41
}

View File

@ -0,0 +1,20 @@
package com.r3.corda.doorman
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class DoormanParametersTest {
@Test
fun `parse arg correctly`() {
val params = DoormanParameters(arrayOf("--keygen", "--keystorePath", "./testDummyPath.jks"))
assertEquals(DoormanParameters.Mode.CA_KEYGEN, params.mode)
assertEquals("./testDummyPath.jks", params.keystorePath.toString())
assertEquals(0, params.port)
val params2 = DoormanParameters(arrayOf("--keystorePath", "./testDummyPath.jks", "--port", "1000"))
assertEquals(DoormanParameters.Mode.DOORMAN, params2.mode)
assertEquals("./testDummyPath.jks", params2.keystorePath.toString())
assertEquals(1000, params2.port)
}
}

View File

@ -31,7 +31,8 @@ class DoormanServiceTest {
private lateinit var doormanServer: DoormanServer
private fun startSigningServer(storage: CertificationRequestStorage) {
doormanServer = DoormanServer(HostAndPort.fromParts("localhost", 0), DoormanWebService(intermediateCA, rootCA.certificate, storage))
doormanServer = DoormanServer(HostAndPort.fromParts("localhost", 0), intermediateCA, rootCA.certificate, storage)
doormanServer.start()
}
@After
@ -85,9 +86,9 @@ class DoormanServiceTest {
assertThat(pollForResponse(id)).isEqualTo(PollResponse.NotReady)
storage.approveRequest(id) {
JcaPKCS10CertificationRequest(it.request).run {
JcaPKCS10CertificationRequest(request).run {
X509Utilities.createServerCert(subject, publicKey, intermediateCA,
if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName), listOf(it.ipAddress))
if (ipAddress == hostName) listOf() else listOf(hostName), listOf(ipAddress))
}
}

View File

@ -133,13 +133,13 @@ class DBCertificateRequestStorageTest {
private fun approveRequest(requestId: String) {
storage.approveRequest(requestId) {
JcaPKCS10CertificationRequest(it.request).run {
JcaPKCS10CertificationRequest(request).run {
X509Utilities.createServerCert(
subject,
publicKey,
intermediateCA,
if (it.ipAddress == it.hostName) listOf() else listOf(it.hostName),
listOf(it.ipAddress))
if (ipAddress == hostName) listOf() else listOf(hostName),
listOf(ipAddress))
}
}
}