Merging signing service and doorman (#72)

* Merging signing service and doorman

* Addressing review comments

* Removing redundant package name space from method call

* Adding description field to gradle
This commit is contained in:
mkit
2017-10-20 17:19:50 +01:00
committed by GitHub
parent 0ae205ec25
commit dfb226fbbb
58 changed files with 372 additions and 5190 deletions

View File

@ -0,0 +1,223 @@
package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage.Companion.DOORMAN_SIGNATURE
import com.r3.corda.networkmanage.common.utils.buildCertPath
import com.r3.corda.networkmanage.common.utils.toX509Certificate
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.node.utilities.CertificateType
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.X509Utilities
import net.corda.node.utilities.configureDatabase
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import org.hibernate.envers.AuditReaderFactory
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.security.KeyPair
import java.util.*
import kotlin.test.*
class DBCertificateRequestStorageTest {
private lateinit var storage: DBCertificateRequestStorage
private lateinit var persistence: CordaPersistence
@Before
fun startDb() {
persistence = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), { throw UnsupportedOperationException() }, SchemaService())
storage = DBCertificateRequestStorage(persistence)
}
@After
fun closeDb() {
persistence.close()
}
@Test
fun `valid request`() {
val request = createRequest("LegalName").first
val requestId = storage.saveRequest(request)
assertNotNull(storage.getRequest(requestId)).apply {
assertEquals(request, PKCS10CertificationRequest(this.request))
}
assertThat(storage.getRequests(RequestStatus.New).map { it.requestId }).containsOnly(requestId)
}
@Test
fun `approve request`() {
val (request, _) = createRequest("LegalName")
// Add request to DB.
val requestId = storage.saveRequest(request)
// Pending request should equals to 1.
assertEquals(1, storage.getRequests(RequestStatus.New).size)
// Certificate should be empty.
assertNull(storage.getRequest(requestId)!!.certificateData)
// Store certificate to DB.
val result = storage.approveRequest(requestId, DOORMAN_SIGNATURE)
// Check request request has been approved
assertTrue(result)
// Check request is not ready yet.
// assertTrue(storage.getResponse(requestId) is CertificateResponse.NotReady)
// New request should be empty.
assertTrue(storage.getRequests(RequestStatus.New).isEmpty())
}
@Test
fun `approve request ignores subsequent approvals`() {
// Given
val (request, _) = createRequest("LegalName")
// Add request to DB.
val requestId = storage.saveRequest(request)
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
// When subsequent approval is performed
val result = storage.approveRequest(requestId, DOORMAN_SIGNATURE)
// Then check request has not been approved
assertFalse(result)
}
@Test
fun `sign request`() {
val (csr, _) = createRequest("LegalName")
// Add request to DB.
val requestId = storage.saveRequest(csr)
// New request should equals to 1.
assertEquals(1, storage.getRequests(RequestStatus.New).size)
// Certificate should be empty.
assertNull(storage.getRequest(requestId)!!.certificateData)
// Store certificate to DB.
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
// Check request is not ready yet.
assertEquals(RequestStatus.Approved, storage.getRequest(requestId)!!.status)
// New request should be empty.
assertTrue(storage.getRequests(RequestStatus.New).isEmpty())
// Sign certificate
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run {
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
}, listOf(DOORMAN_SIGNATURE))
// Check request is ready
assertNotNull(storage.getRequest(requestId)!!.certificateData)
}
@Test
fun `sign request ignores subsequent sign requests`() {
val (csr, _) = createRequest("LegalName")
// Add request to DB.
val requestId = storage.saveRequest(csr)
// Store certificate to DB.
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run {
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
}, listOf(DOORMAN_SIGNATURE))
// Sign certificate
// When subsequent signature requested
assertFailsWith(IllegalArgumentException::class) {
storage.putCertificatePath(requestId, JcaPKCS10CertificationRequest(csr).run {
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
val ourCertificate = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
}, listOf(DOORMAN_SIGNATURE))
}
}
@Test
fun `reject request`() {
val requestId = storage.saveRequest(createRequest("BankA").first)
storage.rejectRequest(requestId, DOORMAN_SIGNATURE, "Because I said so!")
assertThat(storage.getRequests(RequestStatus.New)).isEmpty()
assertThat(storage.getRequest(requestId)!!.remark).isEqualTo("Because I said so!")
}
@Test
fun `request with the same legal name as a pending request`() {
val requestId1 = storage.saveRequest(createRequest("BankA").first)
assertThat(storage.getRequests(RequestStatus.New).map { it.requestId }).containsOnly(requestId1)
val requestId2 = storage.saveRequest(createRequest("BankA").first)
assertThat(storage.getRequests(RequestStatus.New).map { it.requestId }).containsOnly(requestId1)
assertEquals(RequestStatus.Rejected, storage.getRequest(requestId2)!!.status)
assertThat(storage.getRequest(requestId2)!!.remark).containsIgnoringCase("duplicate")
// Make sure the first request is processed properly
storage.approveRequest(requestId1, DOORMAN_SIGNATURE)
assertThat(storage.getRequest(requestId1)!!.status).isEqualTo(RequestStatus.Approved)
}
@Test
fun `request with the same legal name as a previously approved request`() {
val requestId1 = storage.saveRequest(createRequest("BankA").first)
storage.approveRequest(requestId1, DOORMAN_SIGNATURE)
val requestId2 = storage.saveRequest(createRequest("BankA").first)
assertThat(storage.getRequest(requestId2)!!.remark).containsIgnoringCase("duplicate")
}
@Test
fun `request with the same legal name as a previously rejected request`() {
val requestId1 = storage.saveRequest(createRequest("BankA").first)
storage.rejectRequest(requestId1, DOORMAN_SIGNATURE, "Because I said so!")
val requestId2 = storage.saveRequest(createRequest("BankA").first)
assertThat(storage.getRequests(RequestStatus.New).map { it.requestId }).containsOnly(requestId2)
storage.approveRequest(requestId2, DOORMAN_SIGNATURE)
assertThat(storage.getRequest(requestId2)!!.status).isEqualTo(RequestStatus.Approved)
}
@Test
fun `audit data is available for CSRs`() {
// given
val approver = "APPROVER"
// when
val requestId = storage.saveRequest(createRequest("BankA").first)
storage.approveRequest(requestId, approver)
// then
persistence.transaction {
val auditReader = AuditReaderFactory.get(persistence.entityManagerFactory.createEntityManager())
val newRevision = auditReader.find(CertificateSigningRequest::class.java, requestId, 1)
assertEquals(RequestStatus.New, newRevision.status)
assertTrue(newRevision.modifiedBy.isEmpty())
val approvedRevision = auditReader.find(CertificateSigningRequest::class.java, requestId, 2)
assertEquals(RequestStatus.Approved, approvedRevision.status)
assertEquals(approver, approvedRevision.modifiedBy.first())
}
}
private fun createRequest(legalName: String): Pair<PKCS10CertificationRequest, KeyPair> {
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(organisation = legalName, locality = "London", country = "GB"), "my@mail.com", keyPair)
return Pair(request, keyPair)
}
private fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
val props = Properties()
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
props.setProperty("dataSource.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
props.setProperty("dataSource.user", "sa")
props.setProperty("dataSource.password", "")
return props
}
private fun makeTestDatabaseProperties(key: String? = null, value: String? = null): Properties {
val props = Properties()
props.setProperty("transactionIsolationLevel", "repeatableRead") //for other possible values see net.corda.node.utilities.CordaPeristence.parserTransactionIsolationLevel(String)
if (key != null) {
props.setProperty(key, value)
}
return props
}
}

View File

@ -0,0 +1,138 @@
package com.r3.corda.networkmanage.common.persistence
import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage.Companion.DOORMAN_SIGNATURE
import com.r3.corda.networkmanage.common.utils.buildCertPath
import com.r3.corda.networkmanage.common.utils.toX509Certificate
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.sha256
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.serialization.KryoServerSerializationScheme
import net.corda.node.utilities.CertificateType
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.X509Utilities
import net.corda.node.utilities.configureDatabase
import net.corda.nodeapi.internal.serialization.*
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
class PersistenceNodeInfoStorageTest {
private lateinit var nodeInfoStorage: NodeInfoStorage
private lateinit var requestStorage: CertificationRequestStorage
private lateinit var persistence: CordaPersistence
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, CordaX500Name(commonName = "Corda Node Intermediate CA", locality = "London", organisation = "R3 LTD", country = "GB"), intermediateCAKey.public)
companion object {
@BeforeClass
@JvmStatic
fun initSerialization() {
try {
SerializationDefaults.SERIALIZATION_FACTORY = SerializationFactoryImpl().apply {
registerScheme(KryoServerSerializationScheme())
registerScheme(AMQPServerSerializationScheme())
}
SerializationDefaults.P2P_CONTEXT = KRYO_P2P_CONTEXT
SerializationDefaults.RPC_SERVER_CONTEXT = KRYO_RPC_SERVER_CONTEXT
SerializationDefaults.STORAGE_CONTEXT = KRYO_STORAGE_CONTEXT
SerializationDefaults.CHECKPOINT_CONTEXT = KRYO_CHECKPOINT_CONTEXT
} catch (ignored: Exception) {
// Ignored
}
}
}
@Before
fun startDb() {
persistence = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), { throw UnsupportedOperationException() }, SchemaService())
nodeInfoStorage = PersistenceNodeInfoStorage(persistence)
requestStorage = DBCertificateRequestStorage(persistence)
}
@After
fun closeDb() {
persistence.close()
}
@Test
fun `test get CertificatePath`() {
// Create node info.
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val request = X509Utilities.createCertificateSigningRequest(nodeInfo.legalIdentities.first().name, "my@mail.com", keyPair)
val requestId = requestStorage.saveRequest(request)
requestStorage.approveRequest(requestId, DOORMAN_SIGNATURE)
assertNull(nodeInfoStorage.getCertificatePath(keyPair.public.hash()))
requestStorage.putCertificatePath(requestId, buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()), listOf(DOORMAN_SIGNATURE))
val storedCertPath = nodeInfoStorage.getCertificatePath(keyPair.public.hash())
assertNotNull(storedCertPath)
assertEquals(clientCert.toX509Certificate(), storedCertPath!!.certificates.first())
}
@Test
fun `test getNodeInfoHashes`() {
// Create node info.
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
val clientCert2 = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME).public)
val certPath2 = buildCertPath(clientCert2.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val nodeInfoSame = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val nodeInfo2 = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath2)), 1, serial = 1L)
nodeInfoStorage.putNodeInfo(nodeInfo)
nodeInfoStorage.putNodeInfo(nodeInfoSame)
// getNodeInfoHashes should contain 1 hash.
assertEquals(listOf(nodeInfo.serialize().sha256().toString()), nodeInfoStorage.getNodeInfoHashes())
nodeInfoStorage.putNodeInfo(nodeInfo2)
// getNodeInfoHashes should contain 2 hash.
assertEquals(listOf(nodeInfo2.serialize().sha256().toString(), nodeInfo.serialize().sha256().toString()).sorted(), nodeInfoStorage.getNodeInfoHashes().sorted())
// Test retrieve NodeInfo.
assertEquals(nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256().toString()))
assertEquals(nodeInfo2, nodeInfoStorage.getNodeInfo(nodeInfo2.serialize().sha256().toString()))
}
@Test
fun `same pub key with different node info`() {
// Create node info.
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val nodeInfoSamePubKey = NodeInfo(listOf(NetworkHostAndPort("my.company2.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
nodeInfoStorage.putNodeInfo(nodeInfo)
assertEquals(nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256().toString()))
// This should replace the node info.
nodeInfoStorage.putNodeInfo(nodeInfoSamePubKey)
// Old node info should be removed.
assertNull(nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256().toString()))
assertEquals(nodeInfoSamePubKey, nodeInfoStorage.getNodeInfo(nodeInfoSamePubKey.serialize().sha256().toString()))
}
}

View File

@ -0,0 +1,59 @@
package com.r3.corda.networkmanage.doorman
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.times
import com.nhaarman.mockito_kotlin.verify
import com.r3.corda.networkmanage.common.persistence.*
import com.r3.corda.networkmanage.common.utils.buildCertPath
import com.r3.corda.networkmanage.common.utils.toX509Certificate
import com.r3.corda.networkmanage.doorman.signer.DefaultCsrHandler
import com.r3.corda.networkmanage.doorman.signer.Signer
import net.corda.core.crypto.Crypto
import net.corda.core.identity.CordaX500Name
import net.corda.node.utilities.X509Utilities
import org.junit.Test
import kotlin.test.assertEquals
class DefaultRequestProcessorTest {
@Test
fun `get response`() {
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val cert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(locality = "London", organisation = "Test", country = "GB"), keyPair)
val requestStorage: CertificationRequestStorage = mock {
on { getRequest("New") }.thenReturn(CertificateSigningRequest(status = RequestStatus.New))
on { getRequest("Signed") }.thenReturn(CertificateSigningRequest(status = RequestStatus.Signed, certificateData = CertificateData("", buildCertPath(cert.toX509Certificate()).encoded, CertificateStatus.VALID)))
on { getRequest("Rejected") }.thenReturn(CertificateSigningRequest(status = RequestStatus.Rejected, remark = "Random reason"))
}
val signer: Signer = mock()
val requestProcessor = DefaultCsrHandler(requestStorage, signer)
assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("random"))
assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("New"))
assertEquals(CertificateResponse.Ready(buildCertPath(cert.toX509Certificate())), requestProcessor.getResponse("Signed"))
assertEquals(CertificateResponse.Unauthorised("Random reason"), requestProcessor.getResponse("Rejected"))
}
@Test
fun `process request`() {
val request1 = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Test1", country = "GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
val request2 = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Test2", country = "GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
val request3 = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Test3", country = "GB"), "my@email.com", Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
val requestStorage: CertificationRequestStorage = mock {
on { getRequests(RequestStatus.Approved) }.thenReturn(listOf(
CertificateSigningRequest(requestId = "1", request = request1.encoded),
CertificateSigningRequest(requestId = "2", request = request2.encoded),
CertificateSigningRequest(requestId = "3", request = request3.encoded)
))
}
val signer: Signer = mock()
val requestProcessor = DefaultCsrHandler(requestStorage, signer)
requestProcessor.processApprovedRequests()
verify(signer, times(3)).sign(any())
verify(requestStorage, times(1)).getRequests(any())
}
}

View File

@ -0,0 +1,50 @@
package com.r3.corda.networkmanage.doorman
import com.typesafe.config.ConfigException
import org.junit.Test
import java.io.File
import java.nio.file.Paths
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class DoormanParametersTest {
private val testDummyPath = ".${File.separator}testDummyPath.jks"
private val validConfigPath = File(javaClass.getResource("/doorman.conf").toURI()).absolutePath
private val invalidConfigPath = File(javaClass.getResource("/doorman_fail.conf").toURI()).absolutePath
@Test
fun `parse mode flag arg correctly`() {
assertEquals(DoormanParameters.Mode.CA_KEYGEN, parseParameters("--mode", "CA_KEYGEN", "--configFile", validConfigPath).mode)
assertEquals(DoormanParameters.Mode.ROOT_KEYGEN, parseParameters("--mode", "ROOT_KEYGEN", "--configFile", validConfigPath).mode)
assertEquals(DoormanParameters.Mode.DOORMAN, parseParameters("--mode", "DOORMAN", "--configFile", validConfigPath).mode)
}
@Test
fun `command line arg should override config file`() {
val params = parseParameters("--keystorePath", testDummyPath, "--port", "1000", "--configFile", validConfigPath)
assertEquals(testDummyPath, params.keystorePath.toString())
assertEquals(1000, params.port)
val params2 = parseParameters("--configFile", validConfigPath)
assertEquals(Paths.get("/opt/doorman/certificates/caKeystore.jks"), params2.keystorePath)
assertEquals(8080, params2.port)
}
@Test
fun `should fail when config missing`() {
// dataSourceProperties is missing from node_fail.conf and it should fail during parsing, and shouldn't use default from reference.conf.
assertFailsWith<ConfigException.Missing> {
parseParameters("--configFile", invalidConfigPath)
}
}
@Test
fun `should parse jira config correctly`() {
val parameter = parseParameters("--configFile", validConfigPath)
assertEquals("https://doorman-jira-host.com/", parameter.jiraConfig?.address)
assertEquals("TD", parameter.jiraConfig?.projectCode)
assertEquals("username", parameter.jiraConfig?.username)
assertEquals("password", parameter.jiraConfig?.password)
assertEquals(41, parameter.jiraConfig?.doneTransitionCode)
}
}

View File

@ -0,0 +1,169 @@
package com.r3.corda.networkmanage.doorman
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.times
import com.nhaarman.mockito_kotlin.verify
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
import com.r3.corda.networkmanage.common.utils.buildCertPath
import com.r3.corda.networkmanage.common.utils.toX509Certificate
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
import net.corda.core.crypto.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.serialization.KryoServerSerializationScheme
import net.corda.node.utilities.CertificateType
import net.corda.node.utilities.X509Utilities
import net.corda.nodeapi.internal.serialization.*
import org.bouncycastle.asn1.x500.X500Name
import org.codehaus.jackson.map.ObjectMapper
import org.junit.BeforeClass
import org.junit.Test
import java.io.FileNotFoundException
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import javax.ws.rs.core.MediaType
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class NodeInfoWebServiceTest {
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(locality = "London", organisation = "R3 LTD", country = "GB", commonName = "Corda Node Root CA"), rootCAKey)
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
companion object {
@BeforeClass
@JvmStatic
fun initSerialization() {
try {
SerializationDefaults.SERIALIZATION_FACTORY = SerializationFactoryImpl().apply {
registerScheme(KryoServerSerializationScheme())
registerScheme(AMQPServerSerializationScheme())
}
SerializationDefaults.P2P_CONTEXT = KRYO_P2P_CONTEXT
SerializationDefaults.RPC_SERVER_CONTEXT = KRYO_RPC_SERVER_CONTEXT
SerializationDefaults.STORAGE_CONTEXT = KRYO_STORAGE_CONTEXT
SerializationDefaults.CHECKPOINT_CONTEXT = KRYO_CHECKPOINT_CONTEXT
} catch (ignored: Exception) {
// Ignored
}
}
}
@Test
fun `submit nodeInfo`() {
// Create node info.
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
// Create digital signature.
val digitalSignature = DigitalSignature.WithKey(keyPair.public, Crypto.doSign(keyPair.private, nodeInfo.serialize().bytes))
val nodeInfoStorage: NodeInfoStorage = mock {
on { getCertificatePath(any()) }.thenReturn(certPath)
}
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage)).use {
it.start()
val registerURL = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/register")
val nodeInfoAndSignature = SignedData(nodeInfo.serialize(), digitalSignature).serialize().bytes
// Post node info and signature to doorman
doPost(registerURL, nodeInfoAndSignature)
verify(nodeInfoStorage, times(1)).getCertificatePath(any())
}
}
@Test
fun `submit nodeInfo with invalid signature`() {
// Create node info.
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
// Create digital signature.
val attackerKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val digitalSignature = DigitalSignature.WithKey(attackerKeyPair.public, Crypto.doSign(attackerKeyPair.private, nodeInfo.serialize().bytes))
val nodeInfoStorage: NodeInfoStorage = mock {
on { getCertificatePath(any()) }.thenReturn(certPath)
}
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage)).use {
it.start()
val registerURL = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/register")
val nodeInfoAndSignature = SignedData(nodeInfo.serialize(), digitalSignature).serialize().bytes
// Post node info and signature to doorman
assertFailsWith(IOException::class) {
doPost(registerURL, nodeInfoAndSignature)
}
verify(nodeInfoStorage, times(1)).getCertificatePath(any())
}
}
@Test
fun `get network map`() {
val networkMapList = listOf(SecureHash.randomSHA256().toString(), SecureHash.randomSHA256().toString())
val nodeInfoStorage: NodeInfoStorage = mock {
on { getNodeInfoHashes() }.thenReturn(networkMapList)
}
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage)).use {
it.start()
val conn = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}").openConnection() as HttpURLConnection
val response = conn.inputStream.bufferedReader().use { it.readLine() }
val list = ObjectMapper().readValue(response, List::class.java)
verify(nodeInfoStorage, times(1)).getNodeInfoHashes()
assertEquals(networkMapList, list)
}
}
@Test
fun `get node info`() {
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
val nodeInfoHash = nodeInfo.serialize().sha256().toString()
val nodeInfoStorage: NodeInfoStorage = mock {
on { getNodeInfo(nodeInfoHash) }.thenReturn(nodeInfo)
}
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage)).use {
it.start()
val nodeInfoURL = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/$nodeInfoHash")
val conn = nodeInfoURL.openConnection()
val nodeInfoResponse = conn.inputStream.readBytes().deserialize<NodeInfo>()
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
assertEquals(nodeInfo, nodeInfoResponse)
assertFailsWith(FileNotFoundException::class) {
URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/${SecureHash.randomSHA256()}").openConnection().getInputStream()
}
}
}
private fun doPost(url: URL, payload: ByteArray) {
val conn = url.openConnection() as HttpURLConnection
conn.doOutput = true
conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
conn.outputStream.write(payload)
return try {
conn.inputStream.bufferedReader().use { it.readLine() }
} catch (e: IOException) {
throw IOException(conn.errorStream.bufferedReader().readLine(), e)
}
}
}

View File

@ -0,0 +1,206 @@
package com.r3.corda.networkmanage.doorman
import com.nhaarman.mockito_kotlin.*
import com.r3.corda.networkmanage.common.persistence.CertificateResponse
import com.r3.corda.networkmanage.common.utils.buildCertPath
import com.r3.corda.networkmanage.common.utils.toX509Certificate
import com.r3.corda.networkmanage.doorman.signer.CsrHandler
import com.r3.corda.networkmanage.doorman.webservice.RegistrationWebService
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.utilities.CertificateStream
import net.corda.node.utilities.CertificateType
import net.corda.node.utilities.X509Utilities
import net.corda.node.utilities.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.GeneralName
import org.bouncycastle.asn1.x509.GeneralSubtree
import org.bouncycastle.asn1.x509.NameConstraints
import org.bouncycastle.cert.X509CertificateHolder
import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import org.junit.After
import org.junit.Test
import java.io.IOException
import java.net.HttpURLConnection
import java.net.HttpURLConnection.*
import java.net.URL
import java.security.cert.CertPath
import java.security.cert.X509Certificate
import java.util.*
import java.util.zip.ZipInputStream
import javax.ws.rs.core.MediaType
import kotlin.test.assertEquals
class RegistrationWebServiceTest {
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 Ltd", country = "GB"), rootCAKey)
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
private lateinit var doormanServer: DoormanServer
private fun startSigningServer(csrHandler: CsrHandler) {
doormanServer = DoormanServer(NetworkHostAndPort("localhost", 0), RegistrationWebService(csrHandler, DoormanServerStatus()))
doormanServer.start()
}
@After
fun close() {
doormanServer.close()
}
@Test
fun `submit request`() {
val id = SecureHash.randomSHA256().toString()
val requestProcessor = mock<CsrHandler> {
on { saveRequest(any()) }.then { id }
}
startSigningServer(requestProcessor)
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Legal Name", country = "GB"), "my@mail.com", keyPair)
// Post request to signing server via http.
assertEquals(id, submitRequest(request))
verify(requestProcessor, times(1)).saveRequest(any())
submitRequest(request)
verify(requestProcessor, times(2)).saveRequest(any())
}
@Test
fun `retrieve certificate`() {
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
val id = SecureHash.randomSHA256().toString()
// Mock Storage behaviour.
val certificateStore = mutableMapOf<String, CertPath>()
val requestProcessor = mock<CsrHandler> {
on { getResponse(eq(id)) }.then {
certificateStore[id]?.let {
CertificateResponse.Ready(it)
} ?: CertificateResponse.NotReady
}
on { processApprovedRequests() }.then {
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "LegalName", country = "GB"), "my@mail.com", keyPair)
certificateStore[id] = JcaPKCS10CertificationRequest(request).run {
val tlsCert = X509Utilities.createCertificate(CertificateType.TLS, intermediateCACert, intermediateCAKey, subject, publicKey).toX509Certificate()
buildCertPath(tlsCert, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
}
null
}
}
startSigningServer(requestProcessor)
assertThat(pollForResponse(id)).isEqualTo(PollResponse.NotReady)
requestProcessor.processApprovedRequests()
val certificates = (pollForResponse(id) as PollResponse.Ready).certChain
verify(requestProcessor, times(2)).getResponse(any())
assertEquals(3, certificates.size)
certificates.first().run {
assertThat(subjectDN.name).contains("O=LegalName")
assertThat(subjectDN.name).contains("L=London")
}
certificates.last().run {
assertThat(subjectDN.name).contains("CN=Corda Node Root CA")
assertThat(subjectDN.name).contains("L=London")
}
}
@Test
fun `retrieve certificate and create valid TLS certificate`() {
val keyPair = Crypto.generateKeyPair(DEFAULT_TLS_SIGNATURE_SCHEME)
val id = SecureHash.randomSHA256().toString()
// Mock Storage behaviour.
val certificateStore = mutableMapOf<String, CertPath>()
val storage = mock<CsrHandler> {
on { getResponse(eq(id)) }.then {
certificateStore[id]?.let {
CertificateResponse.Ready(it)
} ?: CertificateResponse.NotReady
}
on { processApprovedRequests() }.then {
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(locality = "London", organisation = "Legal Name", country = "GB"), "my@mail.com", keyPair)
certificateStore[id] = JcaPKCS10CertificationRequest(request).run {
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, X500Name("CN=LegalName, L=London")))), arrayOf())
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, subject, publicKey, nameConstraints = nameConstraints).toX509Certificate()
buildCertPath(clientCert, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
}
true
}
}
startSigningServer(storage)
assertThat(pollForResponse(id)).isEqualTo(PollResponse.NotReady)
storage.processApprovedRequests()
val certificates = (pollForResponse(id) as PollResponse.Ready).certChain
verify(storage, times(2)).getResponse(any())
assertEquals(3, certificates.size)
val sslKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val sslCert = X509Utilities.createCertificate(CertificateType.TLS, X509CertificateHolder(certificates.first().encoded), keyPair, X500Name("CN=LegalName,L=London"), sslKey.public).toX509Certificate()
// TODO: This is temporary solution, remove all certificate re-shaping after identity refactoring is done.
X509Utilities.validateCertificateChain(certificates.last(), sslCert, *certificates.toTypedArray())
}
@Test
fun `request not authorised`() {
val id = SecureHash.randomSHA256().toString()
val requestProcessor = mock<CsrHandler> {
on { getResponse(eq(id)) }.then { CertificateResponse.Unauthorised("Not Allowed") }
}
startSigningServer(requestProcessor)
assertThat(pollForResponse(id)).isEqualTo(PollResponse.Unauthorised("Not Allowed"))
}
private fun submitRequest(request: PKCS10CertificationRequest): String {
val conn = URL("http://${doormanServer.hostAndPort}/api/certificate").openConnection() as HttpURLConnection
conn.doOutput = true
conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
conn.outputStream.write(request.encoded)
return conn.inputStream.bufferedReader().use { it.readLine() }
}
private fun pollForResponse(id: String): PollResponse {
val url = URL("http://${doormanServer.hostAndPort}/api/certificate/$id")
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "GET"
return when (conn.responseCode) {
HTTP_OK -> ZipInputStream(conn.inputStream).use {
val stream = CertificateStream(it)
val certificates = ArrayList<X509Certificate>()
while (it.nextEntry != null) {
certificates.add(stream.nextCertificate())
}
PollResponse.Ready(certificates)
}
HTTP_NO_CONTENT -> PollResponse.NotReady
HTTP_UNAUTHORIZED -> PollResponse.Unauthorised(IOUtils.toString(conn.errorStream))
else -> throw IOException("Cannot connect to Certificate Signing Server, HTTP response code : ${conn.responseCode}")
}
}
private interface PollResponse {
object NotReady : PollResponse
data class Ready(val certChain: List<X509Certificate>) : PollResponse
data class Unauthorised(val message: String) : PollResponse
}
}

View File

@ -0,0 +1,109 @@
package com.r3.corda.networkmanage.hsm.authentication
import CryptoServerCXI.CryptoServerCXI
import CryptoServerJCE.CryptoServerProvider
import com.nhaarman.mockito_kotlin.*
import org.junit.Before
import org.junit.Test
import java.io.Console
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class AuthenticatorTest {
private lateinit var provider: CryptoServerProvider
private lateinit var console: Console
@Before
fun setUp() {
provider = mock()
whenever(provider.cryptoServer).thenReturn(mock<CryptoServerCXI>())
console = mock()
}
@Test
fun `connectAndAuthenticate aborts when user inputs Q`() {
// given
givenUserConsoleInputOnReadLine("Q")
var executed = false
// when
Authenticator(provider = provider, console = console).connectAndAuthenticate { _, _ -> executed = true }
// then
assertFalse(executed)
verify(provider, never()).loginPassword(any<String>(), any<String>())
verify(provider, never()).loginSign(any<String>(), any<String>(), any<String>())
}
@Test
fun `connectAndAuthenticate authenticates user with password`() {
// given
val username = "TEST_USER"
val password = "TEST_PASSWORD"
givenUserConsoleInputOnReadLine(username)
givenUserConsoleInputOnReadPassword(password)
givenAuthenticationResult(true)
var executed = false
// when
Authenticator(provider = provider, console = console).connectAndAuthenticate { _, _ -> executed = true }
// then
verify(provider).loginPassword(username, password)
verify(provider, never()).loginSign(any<String>(), any<String>(), any<String>())
assertTrue(executed)
}
@Test
fun `connectAndAuthenticate authenticates user with card reader`() {
// given
val username = "TEST_USER"
givenUserConsoleInputOnReadLine(username)
givenAuthenticationResult(true)
var executed = false
// when
Authenticator(provider = provider, console = console, mode = AuthMode.CARD_READER).connectAndAuthenticate { _, _ -> executed = true }
// then
verify(provider).loginSign(username, ":cs2:cyb:USB0", null)
verify(provider, never()).loginPassword(any<String>(), any<String>())
assertTrue(executed)
}
@Test
fun `connectAndAuthenticate authenticates multiple users with password`() {
// given
val username = "TEST_USER"
val password = "TEST_PASSWORD"
givenUserConsoleInputOnReadLine(username)
givenUserConsoleInputOnReadPassword(password)
givenAuthenticationResult(false, false, true)
var executed = false
// when
Authenticator(provider = provider, console = console).connectAndAuthenticate { _, _ -> executed = true }
// then
verify(provider, times(3)).loginPassword(username, password)
verify(provider, never()).loginSign(any<String>(), any<String>(), any<String>())
assertTrue(executed)
}
private fun givenAuthenticationResult(sufficient: Boolean, vararg subsequent: Boolean) {
val stub = whenever(provider.cryptoServer.authState).thenReturn(if (sufficient) 3 else 0)
subsequent.forEach {
stub.thenReturn(if (it) 3 else 0)
}
}
private fun givenUserConsoleInputOnReadPassword(input: String) {
whenever(console.readPassword(any<String>())).thenReturn(input.toCharArray())
}
private fun givenUserConsoleInputOnReadLine(input: String) {
whenever(console.readLine()).thenReturn(input)
}
}

View File

@ -0,0 +1,36 @@
package com.r3.corda.networkmanage.hsm.configuration
import com.r3.corda.networkmanage.hsm.authentication.AuthMode
import com.typesafe.config.ConfigException
import org.junit.Test
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class ConfigurationTest {
private val validConfigPath = File(javaClass.getResource("/hsm.conf").toURI()).absolutePath
private val invalidConfigPath = File(javaClass.getResource("/hsm_fail.conf").toURI()).absolutePath
@Test
fun `authMode is parsed correctly`() {
val paramsWithPassword = parseParameters("--configFile", validConfigPath, "--authMode", AuthMode.CARD_READER.name)
assertEquals(AuthMode.CARD_READER, paramsWithPassword.authMode)
val paramsWithCardReader = parseParameters("--configFile", validConfigPath, "--authMode", AuthMode.PASSWORD.name)
assertEquals(AuthMode.PASSWORD, paramsWithCardReader.authMode)
}
@Test
fun `validDays duration is parsed correctly`() {
val expectedDuration = 360
val paramsWithPassword = parseParameters("--configFile", validConfigPath, "--validDays", expectedDuration.toString())
assertEquals(expectedDuration, paramsWithPassword.validDays)
}
@Test
fun `should fail when config missing database source properties`() {
// dataSourceProperties is missing from node_fail.conf and it should fail during parsing, and shouldn't use default from reference.conf.
assertFailsWith<ConfigException.Missing> {
parseParameters("--configFile", invalidConfigPath)
}
}
}

View File

@ -0,0 +1,21 @@
keystorePath = "/opt/doorman/certificates/caKeystore.jks"
keyStorePassword = "password"
caPrivateKeyPassword = "password"
host = "localhost"
port = 8080
h2port = 0
dataSourceProperties {
"dataSourceClassName" = org.h2.jdbcx.JdbcDataSource
"dataSource.url" = "jdbc:h2:file:"${basedir}"/persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT="${h2port}
"dataSource.user" = sa
"dataSource.password" = ""
}
jiraConfig{
address = "https://doorman-jira-host.com/"
projectCode = "TD"
username = "username"
password = "password"
doneTransitionCode = 41
}

View File

@ -0,0 +1,6 @@
keystorePath = "/opt/doorman/certificates/caKeystore.jks"
keyStorePassword = "password"
caPrivateKeyPassword = "password"
host = "localhost"
port = 8080
h2port = 0

View File

@ -0,0 +1,12 @@
device = "3001@127.0.0.1"
keyGroup = "*"
keySpecifier = -1
authMode = PASSWORD
h2port = 0
dataSourceProperties {
"dataSourceClassName" = org.h2.jdbcx.JdbcDataSource
"dataSource.url" = "jdbc:h2:file:"${basedir}"/persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT="${h2port}
"dataSource.user" = sa
"dataSource.password" = ""
}

View File

@ -0,0 +1,4 @@
device = "3001@127.0.0.1"
keyGroup = "*"
keySpecifier = -1
authMode = PASSWORD

View File

@ -0,0 +1 @@
mock-maker-inline