Moved the CZ URL and node registration logic of the driver to be more internal, not available through the standard driver call, as these are not testing features for an app dev.

Also cleanup up some of the related tests.
This commit is contained in:
Shams Asari 2017-12-05 16:58:35 +00:00
parent 66515d24b5
commit 89256a7f16
13 changed files with 304 additions and 282 deletions

View File

@ -9,13 +9,13 @@ import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.utilities.trace
import net.corda.nodeapi.internal.crypto.*
import org.bouncycastle.cert.X509CertificateHolder
import org.slf4j.LoggerFactory
import java.nio.file.Path
import java.security.cert.Certificate
import java.security.cert.X509Certificate
object ServiceIdentityGenerator {
private val log = LoggerFactory.getLogger(javaClass)
/**
* Generates signing key pairs and a common distributed service identity for a set of nodes.
* The key pairs and the group identity get serialized to disk in the corresponding node directories.
@ -24,25 +24,21 @@ object ServiceIdentityGenerator {
* @param dirs List of node directories to place the generated identity and key pairs in.
* @param serviceName The legal name of the distributed service.
* @param threshold The threshold for the generated group [CompositeKey].
* @param rootCertertificate the certificate to use a Corda root CA. If not specified the one in
* net/corda/node/internal/certificates/cordadevcakeys.jks is used.
* @param customRootCert the certificate to use a Corda root CA. If not specified the one in
* certificates/cordadevcakeys.jks is used.
*/
fun generateToDisk(dirs: List<Path>,
serviceName: CordaX500Name,
serviceId: String,
threshold: Int = 1,
rootCertertificate: X509CertificateHolder? = null): Party {
customRootCert: X509Certificate? = null): Party {
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
val keyPairs = (1..dirs.size).map { generateKeyPair() }
val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold)
val caKeyStore = loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/cordadevcakeys.jks"), "cordacadevpass")
val issuer = caKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, "cordacadevkeypass")
val rootCert: Certificate = if (rootCertertificate != null) {
rootCertertificate.cert
} else {
caKeyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)
}
val rootCert = customRootCert ?: caKeyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)
keyPairs.zip(dirs) { keyPair, dir ->
val serviceKeyCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, issuer.certificate, issuer.keyPair, serviceName, keyPair.public)

View File

@ -15,5 +15,5 @@ interface SSLConfiguration {
interface NodeSSLConfiguration : SSLConfiguration {
val baseDirectory: Path
override val certificatesDirectory: Path get() = baseDirectory / "certificates"
val rootCaCertFile: Path get() = certificatesDirectory / "rootcacert.cer"
val rootCertFile: Path get() = certificatesDirectory / "rootcert.pem"
}

View File

@ -4,8 +4,8 @@ import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SignatureScheme
import net.corda.core.crypto.random63BitValue
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.internal.read
import net.corda.core.internal.write
import net.corda.core.internal.x500Name
import net.corda.core.utilities.days
import net.corda.core.utilities.millis
@ -27,10 +27,8 @@ import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder
import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder
import org.bouncycastle.util.io.pem.PemReader
import java.io.FileWriter
import java.io.InputStream
import java.math.BigInteger
import java.nio.file.Files
import java.nio.file.Path
import java.security.KeyPair
import java.security.PublicKey
@ -164,7 +162,7 @@ object X509Utilities {
* @param file Target file.
*/
@JvmStatic
fun saveCertificateAsPEMFile(x509Certificate: X509CertificateHolder, file: Path) {
fun saveCertificateAsPEMFile(x509Certificate: X509Certificate, file: Path) {
JcaPEMWriter(file.toFile().writer()).use {
it.writeObject(x509Certificate)
}
@ -176,14 +174,14 @@ object X509Utilities {
* @return The X509Certificate that was encoded in the file.
*/
@JvmStatic
fun loadCertificateFromPEMFile(file: Path): X509CertificateHolder {
val cert = file.read {
fun loadCertificateFromPEMFile(file: Path): X509Certificate {
return file.read {
val reader = PemReader(it.reader())
val pemObject = reader.readPemObject()
X509CertificateHolder(pemObject.content)
val certHolder = X509CertificateHolder(pemObject.content)
certHolder.isValidOn(Date())
certHolder.cert
}
cert.isValidOn(Date())
return cert
}
/**

View File

@ -71,7 +71,7 @@ class X509UtilitiesTest {
fun `load and save a PEM file certificate`() {
val tmpCertificateFile = tempFile("cacert.pem")
val caKey = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val caCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Test Cert", organisation = "R3 Ltd", locality = "London", country = "GB"), caKey)
val caCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Test Cert", organisation = "R3 Ltd", locality = "London", country = "GB"), caKey).cert
X509Utilities.saveCertificateAsPEMFile(caCert, tmpCertificateFile)
val readCertificate = X509Utilities.loadCertificateFromPEMFile(tmpCertificateFile)
assertEquals(caCert, readCertificate)

View File

@ -4,85 +4,96 @@ import net.corda.core.node.NodeInfo
import net.corda.core.utilities.seconds
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.driver.CompatibilityZoneParams
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.PortAllocation
import net.corda.testing.driver.driver
import net.corda.testing.driver.internalDriver
import net.corda.testing.node.network.NetworkMapServer
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.net.URL
// TODO There is a unit test class with the same name. Rename this to something else.
class NetworkMapClientTest {
private val cacheTimeout = 1.seconds
private val portAllocation = PortAllocation.Incremental(10000)
private lateinit var networkMapServer: NetworkMapServer
private lateinit var compatibilityZone: CompatibilityZoneParams
@Before
fun start() {
networkMapServer = NetworkMapServer(cacheTimeout, portAllocation.nextHostAndPort())
val address = networkMapServer.start()
compatibilityZone = CompatibilityZoneParams(URL("http://$address"), rootCert = null)
}
@After
fun cleanUp() {
networkMapServer.close()
}
@Test
fun `nodes can see each other using the http network map`() {
NetworkMapServer(1.seconds, portAllocation.nextHostAndPort()).use {
val (host, port) = it.start()
driver(portAllocation = portAllocation, compatibilityZoneURL = URL("http://$host:$port")) {
val alice = startNode(providedName = ALICE.name)
val bob = startNode(providedName = BOB.name)
internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone) {
val alice = startNode(providedName = ALICE.name)
val bob = startNode(providedName = BOB.name)
val notaryNode = defaultNotaryNode.get()
val aliceNode = alice.get()
val bobNode = bob.get()
val notaryNode = defaultNotaryNode.get()
val aliceNode = alice.get()
val bobNode = bob.get()
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
}
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
}
}
@Test
fun `nodes process network map add updates correctly when adding new node to network map`() {
NetworkMapServer(1.seconds, portAllocation.nextHostAndPort()).use {
val (host, port) = it.start()
driver(portAllocation = portAllocation, compatibilityZoneURL = URL("http://$host:$port")) {
val alice = startNode(providedName = ALICE.name)
val notaryNode = defaultNotaryNode.get()
val aliceNode = alice.get()
internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone) {
val alice = startNode(providedName = ALICE.name)
val notaryNode = defaultNotaryNode.get()
val aliceNode = alice.get()
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo)
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo)
val bob = startNode(providedName = BOB.name)
val bobNode = bob.get()
val bob = startNode(providedName = BOB.name)
val bobNode = bob.get()
// Wait for network map client to poll for the next update.
Thread.sleep(2.seconds.toMillis())
// Wait for network map client to poll for the next update.
Thread.sleep(cacheTimeout.toMillis() * 2)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
}
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
}
}
@Test
fun `nodes process network map remove updates correctly`() {
NetworkMapServer(1.seconds, portAllocation.nextHostAndPort()).use {
val (host, port) = it.start()
driver(portAllocation = portAllocation, compatibilityZoneURL = URL("http://$host:$port")) {
val alice = startNode(providedName = ALICE.name)
val bob = startNode(providedName = BOB.name)
internalDriver(portAllocation = portAllocation, compatibilityZone = compatibilityZone) {
val alice = startNode(providedName = ALICE.name)
val bob = startNode(providedName = BOB.name)
val notaryNode = defaultNotaryNode.get()
val aliceNode = alice.get()
val bobNode = bob.get()
val notaryNode = defaultNotaryNode.get()
val aliceNode = alice.get()
val bobNode = bob.get()
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
notaryNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
aliceNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, aliceNode.nodeInfo, bobNode.nodeInfo)
it.removeNodeInfo(aliceNode.nodeInfo)
networkMapServer.removeNodeInfo(aliceNode.nodeInfo)
// Wait for network map client to poll for the next update.
Thread.sleep(2.seconds.toMillis())
// Wait for network map client to poll for the next update.
Thread.sleep(cacheTimeout.toMillis() * 2)
notaryNode.onlySees(notaryNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, bobNode.nodeInfo)
}
notaryNode.onlySees(notaryNode.nodeInfo, bobNode.nodeInfo)
bobNode.onlySees(notaryNode.nodeInfo, bobNode.nodeInfo)
}
}

View File

@ -4,7 +4,7 @@ import net.corda.core.crypto.Crypto
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.internal.toX509CertHolder
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.minutes
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType
@ -13,12 +13,11 @@ import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
import net.corda.testing.ALICE_NAME
import net.corda.testing.driver.CompatibilityZoneParams
import net.corda.testing.driver.PortAllocation
import net.corda.testing.driver.driver
import net.corda.testing.driver.internalDriver
import net.corda.testing.node.network.NetworkMapServer
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.bouncycastle.pkcs.PKCS10CertificationRequest
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
import org.junit.After
@ -30,37 +29,26 @@ import java.net.URL
import java.security.KeyPair
import java.security.cert.CertPath
import java.security.cert.Certificate
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import javax.ws.rs.*
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
private const val REQUEST_ID = "requestId"
private val x509CertificateFactory = X509CertificateFactory()
private val portAllocation = PortAllocation.Incremental(13000)
/**
* Driver based tests for [NetworkRegistrationHelper]
*/
// TODO Rename this to NodeRegistrationTest
class NetworkRegistrationHelperDriverTest {
val rootCertAndKeyPair = createSelfKeyAndSelfSignedCertificate()
val rootCert = rootCertAndKeyPair.certificate
val handler = RegistrationHandler(rootCertAndKeyPair)
lateinit var server: NetworkMapServer
lateinit var host: String
var port: Int = 0
val compatibilityZoneUrl get() = URL("http", host, port, "")
private val portAllocation = PortAllocation.Incremental(13000)
private val rootCertAndKeyPair = createSelfKeyAndSelfSignedCertificate()
private val registrationHandler = RegistrationHandler(rootCertAndKeyPair)
private lateinit var server: NetworkMapServer
private lateinit var compatibilityZone: CompatibilityZoneParams
@Before
fun startServer() {
server = NetworkMapServer(1.minutes, portAllocation.nextHostAndPort(), handler)
val (host, port) = server.start()
this.host = host
this.port = port
server = NetworkMapServer(1.minutes, portAllocation.nextHostAndPort(), registrationHandler)
val address = server.start()
compatibilityZone = CompatibilityZoneParams(URL("http://$address"), rootCertAndKeyPair.certificate.cert)
}
@After
@ -68,115 +56,84 @@ class NetworkRegistrationHelperDriverTest {
server.close()
}
// TODO Ideally this test should be checking that two nodes that register are able to transact with each other. However
// starting a second node hangs so that needs to be fixed.
@Test
fun `node registration correct root cert`() {
driver(portAllocation = portAllocation,
compatibilityZoneURL = compatibilityZoneUrl,
startNodesInProcess = true,
rootCertificate = rootCert
internalDriver(
portAllocation = portAllocation,
notarySpecs = emptyList(),
compatibilityZone = compatibilityZone
) {
startNode(providedName = ALICE_NAME, initialRegistration = true).get()
}
// We're getting:
// a request to sign the certificate then
// at least one poll request to see if the request has been approved.
// all the network map registration and download.
assertThat(handler.requests).startsWith("/certificate", "/certificate/" + REQUEST_ID)
}
@Test
fun `node registration without root cert`() {
driver(portAllocation = portAllocation,
compatibilityZoneURL = compatibilityZoneUrl,
startNodesInProcess = true
) {
assertThatThrownBy {
startNode(providedName = ALICE_NAME, initialRegistration = true).get()
}.isInstanceOf(java.nio.file.NoSuchFileException::class.java)
startNode(providedName = CordaX500Name("Alice", "London", "GB")).getOrThrow()
assertThat(registrationHandler.idsPolled).contains("Alice")
}
}
@Test
fun `node registration wrong root cert`() {
driver(portAllocation = portAllocation,
compatibilityZoneURL = compatibilityZoneUrl,
startNodesInProcess = true,
rootCertificate = createSelfKeyAndSelfSignedCertificate().certificate
) {
assertThatThrownBy {
startNode(providedName = ALICE_NAME, initialRegistration = true).get()
}.isInstanceOf(WrongRootCaCertificateException::class.java)
}
private fun createSelfKeyAndSelfSignedCertificate(): CertificateAndKeyPair {
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate(
CordaX500Name(
commonName = "Integration Test Corda Node Root CA",
organisation = "R3 Ltd",
locality = "London",
country = "GB"),
rootCAKey)
return CertificateAndKeyPair(rootCACert, rootCAKey)
}
}
/**
* Simple registration handler which can handle a single request, which will be given request id [REQUEST_ID].
*/
@Path("certificate")
class RegistrationHandler(private val certificateAndKeyPair: CertificateAndKeyPair) {
val requests = mutableListOf<String>()
lateinit var certificationRequest: JcaPKCS10CertificationRequest
class RegistrationHandler(private val rootCertAndKeyPair: CertificateAndKeyPair) {
private val certPaths = HashMap<String, CertPath>()
val idsPolled = HashSet<String>()
@POST
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
@Produces(MediaType.TEXT_PLAIN)
fun registration(input: InputStream): Response {
requests += "/certificate"
certificationRequest = input.use { JcaPKCS10CertificationRequest(it.readBytes()) }
return Response.ok(REQUEST_ID).build()
val certificationRequest = input.use { JcaPKCS10CertificationRequest(it.readBytes()) }
val (certPath, name) = createSignedClientCertificate(
certificationRequest,
rootCertAndKeyPair.keyPair,
arrayOf(rootCertAndKeyPair.certificate.cert))
certPaths[name.organisation] = certPath
return Response.ok(name.organisation).build()
}
@GET
@Path(REQUEST_ID)
fun reply(): Response {
requests += "/certificate/" + REQUEST_ID
val certPath = createSignedClientCertificate(certificationRequest,
certificateAndKeyPair.keyPair, arrayOf(certificateAndKeyPair.certificate.cert))
return buildDoormanReply(certPath.certificates.toTypedArray())
@Path("{id}")
fun reply(@PathParam("id") id: String): Response {
idsPolled += id
return buildResponse(certPaths[id]!!.certificates)
}
}
// TODO this logic is shared with doorman itself, refactor this to be somewhere where both doorman and these tests
// can depend on
private fun createSignedClientCertificate(certificationRequest: PKCS10CertificationRequest,
caKeyPair: KeyPair,
caCertPath: Array<Certificate>): CertPath {
val request = JcaPKCS10CertificationRequest(certificationRequest)
val x509CertificateHolder = X509Utilities.createCertificate(CertificateType.CLIENT_CA,
caCertPath.first().toX509CertHolder(),
caKeyPair,
CordaX500Name.parse(request.subject.toString()).copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN),
request.publicKey,
nameConstraints = null)
return x509CertificateFactory.generateCertPath(x509CertificateHolder.cert, *caCertPath)
}
// TODO this logic is shared with doorman itself, refactor this to be somewhere where both doorman and these tests
// can depend on
private fun buildDoormanReply(certificates: Array<Certificate>): Response {
// Write certificate chain to a zip stream and extract the bit array output.
val baos = ByteArrayOutputStream()
ZipOutputStream(baos).use { zip ->
// Client certificate must come first and root certificate should come last.
listOf(CORDA_CLIENT_CA, CORDA_INTERMEDIATE_CA, CORDA_ROOT_CA).zip(certificates).forEach {
zip.putNextEntry(ZipEntry("${it.first}.cer"))
zip.write(it.second.encoded)
zip.closeEntry()
private fun buildResponse(certificates: List<Certificate>): Response {
val baos = ByteArrayOutputStream()
ZipOutputStream(baos).use { zip ->
listOf(CORDA_CLIENT_CA, CORDA_INTERMEDIATE_CA, CORDA_ROOT_CA).zip(certificates).forEach {
zip.putNextEntry(ZipEntry("${it.first}.cer"))
zip.write(it.second.encoded)
zip.closeEntry()
}
}
return Response.ok(baos.toByteArray())
.type("application/zip")
.header("Content-Disposition", "attachment; filename=\"certificates.zip\"").build()
}
return Response.ok(baos.toByteArray())
.type("application/zip")
.header("Content-Disposition", "attachment; filename=\"certificates.zip\"").build()
}
private fun createSelfKeyAndSelfSignedCertificate(): CertificateAndKeyPair {
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val rootCACert = X509Utilities.createSelfSignedCACertificate(
CordaX500Name(commonName = "Integration Test Corda Node Root CA",
organisation = "R3 Ltd", locality = "London",
country = "GB"), rootCAKey)
return CertificateAndKeyPair(rootCACert, rootCAKey)
private fun createSignedClientCertificate(certificationRequest: PKCS10CertificationRequest,
caKeyPair: KeyPair,
caCertPath: Array<Certificate>): Pair<CertPath, CordaX500Name> {
val request = JcaPKCS10CertificationRequest(certificationRequest)
val name = CordaX500Name.parse(request.subject.toString())
val x509CertificateHolder = X509Utilities.createCertificate(CertificateType.CLIENT_CA,
caCertPath.first().toX509CertHolder(),
caKeyPair,
name,
request.publicKey,
nameConstraints = null)
val certPath = X509CertificateFactory().generateCertPath(x509CertificateHolder.cert, *caCertPath)
return Pair(certPath, name)
}
}

View File

@ -28,10 +28,18 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
val SELF_SIGNED_PRIVATE_KEY = "Self Signed Private Key"
}
init {
require(config.rootCertFile.exists()) {
"${config.rootCertFile} does not exist. This file must contain the root CA cert of your compatibility zone. " +
"Please contact your CZ operator."
}
}
private val requestIdStore = config.certificatesDirectory / "certificate-request-id.txt"
private val keystorePassword = config.keyStorePassword
// TODO: Use different password for private key.
private val privateKeyPassword = config.keyStorePassword
private val rootCert = X509Utilities.loadCertificateFromPEMFile(config.rootCertFile)
/**
* Ensure the initial keystore for a node is set up; note that this function may cause the process to exit under
@ -106,12 +114,11 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
/**
* Checks that the passed Certificate is the expected root CA.
* @throws WrongRootCaCertificateException if the certificates don't match.
* @throws WrongRootCertException if the certificates don't match.
*/
private fun checkReturnedRootCaMatchesExpectedCa(returnedRootCa: Certificate) {
val expected = X509Utilities.loadCertificateFromPEMFile(config.rootCaCertFile).cert
if (expected != returnedRootCa) {
throw WrongRootCaCertificateException(expected, returnedRootCa, config.rootCaCertFile)
if (rootCert != returnedRootCa) {
throw WrongRootCertException(rootCert, returnedRootCa, config.rootCertFile)
}
}
@ -173,9 +180,9 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
* Exception thrown when the doorman root certificate doesn't match the expected (out-of-band) root certificate.
* This usually means the has been a Man-in-the-middle attack when contacting the doorman.
*/
class WrongRootCaCertificateException(expected: Certificate,
actual: Certificate,
expectedFilePath: Path):
class WrongRootCertException(expected: Certificate,
actual: Certificate,
expectedFilePath: Path):
Exception("""
The Root CA returned back from the registration process does not match the expected Root CA
expected: $expected

View File

@ -1,53 +1,56 @@
package net.corda.node.utilities.registration
import com.nhaarman.mockito_kotlin.*
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.eq
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.*
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.getX509Certificate
import net.corda.nodeapi.internal.crypto.loadKeyStore
import net.corda.testing.ALICE
import net.corda.testing.rigorousMock
import net.corda.testing.testNodeConfiguration
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x500.style.BCStyle
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.security.cert.Certificate
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
val X500Name.commonName: String? get() = getRDNs(BCStyle.CN).firstOrNull()?.first?.value?.toString()
class NetworkRegistrationHelperTest {
@Rule
@JvmField
val tempFolder = TemporaryFolder()
@Test
fun buildKeyStore() {
val id = SecureHash.randomSHA256().toString()
private val requestId = SecureHash.randomSHA256().toString()
private lateinit var config: NodeConfiguration
@Before
fun init() {
config = testNodeConfiguration(baseDirectory = tempFolder.root.toPath(), myLegalName = ALICE.name)
}
@Test
fun `successful registration`() {
val identities = listOf("CORDA_CLIENT_CA",
"CORDA_INTERMEDIATE_CA",
"CORDA_ROOT_CA")
.map { CordaX500Name(commonName = it, organisation = "R3 Ltd", locality = "London", country = "GB") }
val certs = identities.stream().map { X509Utilities.createSelfSignedCACertificate(it, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) }
.map { it.cert }.toTypedArray()
val certService = rigorousMock<NetworkRegistrationService>().also {
doReturn(id).whenever(it).submitRequest(any())
doReturn(certs).whenever(it).retrieveCertificates(eq(id))
}
val config = testNodeConfiguration(
baseDirectory = tempFolder.root.toPath(),
myLegalName = ALICE.name)
val certService = mockRegistrationResponse(*certs)
config.rootCaCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(certs.last().toX509CertHolder(), config.rootCaCertFile)
config.rootCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(certs.last(), config.rootCertFile)
assertFalse(config.nodeKeystore.exists())
assertFalse(config.sslKeystore.exists())
@ -92,4 +95,44 @@ class NetworkRegistrationHelperTest {
assertTrue(containsAlias(X509Utilities.CORDA_ROOT_CA))
}
}
@Test
fun `rootCertFile doesn't exist`() {
val certService = rigorousMock<NetworkRegistrationService>()
assertThatThrownBy {
NetworkRegistrationHelper(config, certService)
}.hasMessageContaining(config.rootCertFile.toString())
}
@Test
fun `root cert in response doesn't match expected`() {
val identities = listOf("CORDA_CLIENT_CA",
"CORDA_INTERMEDIATE_CA",
"CORDA_ROOT_CA")
.map { CordaX500Name(commonName = it, organisation = "R3 Ltd", locality = "London", country = "GB") }
val certs = identities.stream().map { X509Utilities.createSelfSignedCACertificate(it, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) }
.map { it.cert }.toTypedArray()
val certService = mockRegistrationResponse(*certs)
config.rootCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(
X509Utilities.createSelfSignedCACertificate(
CordaX500Name("CORDA_ROOT_CA", "R3 Ltd", "London", "GB"),
Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)).cert,
config.rootCertFile
)
assertThatThrownBy {
NetworkRegistrationHelper(config, certService).buildKeystore()
}.isInstanceOf(WrongRootCertException::class.java)
}
private fun mockRegistrationResponse(vararg response: Certificate): NetworkRegistrationService {
return rigorousMock<NetworkRegistrationService>().also {
doReturn(requestId).whenever(it).submitRequest(any())
doReturn(response).whenever(it).retrieveCertificates(eq(requestId))
}
}
}

View File

@ -76,8 +76,8 @@ class DriverTests {
assertThat(baseDirectory / "process-id").exists()
}
val baseDirectory = driver(notarySpecs = listOf(NotarySpec(DUMMY_NOTARY.name))) {
(this as DriverDSL).baseDirectory(DUMMY_NOTARY.name)
val baseDirectory = internalDriver(notarySpecs = listOf(NotarySpec(DUMMY_NOTARY.name))) {
baseDirectory(DUMMY_NOTARY.name)
}
assertThat(baseDirectory / "process-id").doesNotExist()
}

View File

@ -48,7 +48,6 @@ import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
import net.corda.testing.node.NotarySpec
import okhttp3.OkHttpClient
import okhttp3.Request
import org.bouncycastle.cert.X509CertificateHolder
import org.slf4j.Logger
import rx.Observable
import rx.observables.ConnectableObservable
@ -57,6 +56,7 @@ import java.net.*
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
import java.security.cert.X509Certificate
import java.time.Duration
import java.time.Instant
import java.time.ZoneOffset.UTC
@ -165,8 +165,8 @@ interface DriverDSLExposedInterface : CordformContext {
verifierType: VerifierType = defaultParameters.verifierType,
customOverrides: Map<String, Any?> = defaultParameters.customOverrides,
startInSameProcess: Boolean? = defaultParameters.startInSameProcess,
maximumHeapSize: String = defaultParameters.maximumHeapSize,
initialRegistration: Boolean = defaultParameters.initialRegistration): CordaFuture<NodeHandle>
maximumHeapSize: String = defaultParameters.maximumHeapSize
): CordaFuture<NodeHandle>
/**
@ -301,8 +301,7 @@ data class NodeParameters(
val verifierType: VerifierType = VerifierType.InMemory,
val customOverrides: Map<String, Any?> = emptyMap(),
val startInSameProcess: Boolean? = null,
val maximumHeapSize: String = "200m",
val initialRegistration: Boolean = false
val maximumHeapSize: String = "200m"
) {
fun setProvidedName(providedName: CordaX500Name?) = copy(providedName = providedName)
fun setRpcUsers(rpcUsers: List<User>) = copy(rpcUsers = rpcUsers)
@ -339,13 +338,9 @@ data class NodeParameters(
* not. Note that this may be overridden in [DriverDSLExposedInterface.startNode].
* @param notarySpecs The notaries advertised for this network. These nodes will be started automatically and will be
* available from [DriverDSLExposedInterface.notaryHandles]. Defaults to a simple validating notary.
* @param compatibilityZoneURL if not null each node is started once in registration mode (which makes the node register and quit),
* and then re-starts the node with the given parameters.
* @param rootCertificate if not null every time a node is started for registration that certificate is written on disk
* @param dsl The dsl itself.
* @return The value returned in the [dsl] closure.
*/
// TODO: make the registration testing parameters internal.
fun <A> driver(
defaultParameters: DriverParameters = DriverParameters(),
isDebug: Boolean = defaultParameters.isDebug,
@ -359,8 +354,6 @@ fun <A> driver(
waitForAllNodesToFinish: Boolean = defaultParameters.waitForNodesToFinish,
notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs,
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
compatibilityZoneURL: URL? = defaultParameters.compatibilityZoneURL,
rootCertificate: X509CertificateHolder? = defaultParameters.rootCertificate,
dsl: DriverDSLExposedInterface.() -> A
): A {
return genericDriver(
@ -375,8 +368,51 @@ fun <A> driver(
waitForNodesToFinish = waitForAllNodesToFinish,
notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan,
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
compatibilityZone = null
),
coerce = { it },
dsl = dsl,
initialiseSerialization = initialiseSerialization
)
}
// TODO Move CompatibilityZoneParams and internalDriver into internal package
/**
* @property url The base CZ URL for registration and network map updates
* @property rootCert If specified then the node will register itself using [url] and expect the registration response
* to be rooted at this cert.
*/
data class CompatibilityZoneParams(val url: URL, val rootCert: X509Certificate?)
fun <A> internalDriver(
isDebug: Boolean = DriverParameters().isDebug,
driverDirectory: Path = DriverParameters().driverDirectory,
portAllocation: PortAllocation = DriverParameters().portAllocation,
debugPortAllocation: PortAllocation = DriverParameters().debugPortAllocation,
systemProperties: Map<String, String> = DriverParameters().systemProperties,
useTestClock: Boolean = DriverParameters().useTestClock,
initialiseSerialization: Boolean = DriverParameters().initialiseSerialization,
startNodesInProcess: Boolean = DriverParameters().startNodesInProcess,
waitForAllNodesToFinish: Boolean = DriverParameters().waitForNodesToFinish,
notarySpecs: List<NotarySpec> = DriverParameters().notarySpecs,
extraCordappPackagesToScan: List<String> = DriverParameters().extraCordappPackagesToScan,
compatibilityZone: CompatibilityZoneParams? = null,
dsl: DriverDSL.() -> A
): A {
return genericDriver(
driverDsl = DriverDSL(
portAllocation = portAllocation,
debugPortAllocation = debugPortAllocation,
systemProperties = systemProperties,
driverDirectory = driverDirectory.toAbsolutePath(),
useTestClock = useTestClock,
isDebug = isDebug,
startNodesInProcess = startNodesInProcess,
waitForNodesToFinish = waitForAllNodesToFinish,
notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan,
compatibilityZone = compatibilityZone
),
coerce = { it },
dsl = dsl,
@ -411,9 +447,7 @@ data class DriverParameters(
val startNodesInProcess: Boolean = false,
val waitForNodesToFinish: Boolean = false,
val notarySpecs: List<NotarySpec> = listOf(NotarySpec(DUMMY_NOTARY.name)),
val extraCordappPackagesToScan: List<String> = emptyList(),
val compatibilityZoneURL: URL? = null,
val rootCertificate: X509CertificateHolder? = null
val extraCordappPackagesToScan: List<String> = emptyList()
) {
fun setIsDebug(isDebug: Boolean) = copy(isDebug = isDebug)
fun setDriverDirectory(driverDirectory: Path) = copy(driverDirectory = driverDirectory)
@ -426,8 +460,6 @@ data class DriverParameters(
fun setTerminateNodesOnShutdown(terminateNodesOnShutdown: Boolean) = copy(waitForNodesToFinish = terminateNodesOnShutdown)
fun setNotarySpecs(notarySpecs: List<NotarySpec>) = copy(notarySpecs = notarySpecs)
fun setExtraCordappPackagesToScan(extraCordappPackagesToScan: List<String>) = copy(extraCordappPackagesToScan = extraCordappPackagesToScan)
fun setCompatibilityZoneURL(compatibilityZoneURL: URL?) = copy(compatibilityZoneURL = compatibilityZoneURL)
fun setRootCertificate(rootCertificate: X509CertificateHolder?) = copy(rootCertificate = rootCertificate)
}
/**
@ -480,10 +512,9 @@ fun <DI : DriverDSLExposedInterface, D : DriverDSLInternalInterface, A> genericD
startNodesInProcess: Boolean = defaultParameters.startNodesInProcess,
notarySpecs: List<NotarySpec>,
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
compatibilityZoneURL: URL? = defaultParameters.compatibilityZoneURL,
rootCertificate: X509CertificateHolder? = defaultParameters.rootCertificate,
driverDslWrapper: (DriverDSL) -> D,
coerce: (D) -> DI, dsl: DI.() -> A
coerce: (D) -> DI,
dsl: DI.() -> A
): A {
val serializationEnv = setGlobalSerialization(initialiseSerialization)
val driverDsl = driverDslWrapper(
@ -498,8 +529,7 @@ fun <DI : DriverDSLExposedInterface, D : DriverDSLInternalInterface, A> genericD
waitForNodesToFinish = waitForNodesToFinish,
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
compatibilityZone = null
)
)
val shutdownHook = addShutdownHook(driverDsl::shutdown)
@ -606,8 +636,7 @@ class DriverDSL(
val waitForNodesToFinish: Boolean,
extraCordappPackagesToScan: List<String>,
val notarySpecs: List<NotarySpec>,
val compatibilityZoneURL: URL?,
val rootCertificate: X509CertificateHolder?
val compatibilityZone: CompatibilityZoneParams?
) : DriverDSLInternalInterface {
private var _executorService: ScheduledExecutorService? = null
val executorService get() = _executorService!!
@ -679,16 +708,14 @@ class DriverDSL(
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String,
initialRegistration: Boolean
maximumHeapSize: String
): CordaFuture<NodeHandle> {
val p2pAddress = portAllocation.nextHostAndPort()
// TODO: Derive name from the full picked name, don't just wrap the common name
val name = providedName ?: CordaX500Name(organisation = "${oneOf(names).organisation}-${p2pAddress.port}", locality = "London", country = "GB")
val registrationFuture = if (initialRegistration) {
compatibilityZoneURL ?: throw IllegalArgumentException("Compatibility zone URL must be provided for initial registration.")
registerNode(name, compatibilityZoneURL)
val registrationFuture = if (compatibilityZone?.rootCert != null) {
nodeRegistration(name, compatibilityZone.rootCert, compatibilityZone.url)
} else {
doneFuture(Unit)
}
@ -709,8 +736,8 @@ class DriverDSL(
val config = ConfigHelper.loadConfig(
baseDirectory = baseDirectory(name),
allowMissingConfig = true,
configOverrides = if (compatibilityZoneURL != null) {
configMap + mapOf("compatibilityZoneURL" to compatibilityZoneURL.toString())
configOverrides = if (compatibilityZone != null) {
configMap + mapOf("compatibilityZoneURL" to compatibilityZone.url.toString())
} else {
configMap
}
@ -719,14 +746,10 @@ class DriverDSL(
}
}
private fun writeRootCaCertificateForNode(path: Path, caRootCertificate: X509CertificateHolder) {
path.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(caRootCertificate, path)
}
private fun registerNode(providedName: CordaX500Name, compatibilityZoneURL: URL): CordaFuture<Unit> {
private fun nodeRegistration(providedName: CordaX500Name, rootCert: X509Certificate, compatibilityZoneURL: URL): CordaFuture<Unit> {
val baseDirectory = baseDirectory(providedName).createDirectories()
val config = ConfigHelper.loadConfig(
baseDirectory = baseDirectory(providedName),
baseDirectory = baseDirectory,
allowMissingConfig = true,
configOverrides = configOf(
"p2pAddress" to "localhost:1222", // required argument, not really used
@ -734,16 +757,17 @@ class DriverDSL(
"myLegalName" to providedName.toString())
)
val configuration = config.parseAsNodeConfiguration()
// If a rootCertificate is specified, put that in the node expected path.
rootCertificate?.let { writeRootCaCertificateForNode(configuration.rootCaCertFile, it) }
if (startNodesInProcess) {
configuration.rootCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(rootCert, configuration.rootCertFile)
return if (startNodesInProcess) {
// This is a bit cheating, we're not starting a full node, we're just calling the code nodes call
// when registering.
NetworkRegistrationHelper(configuration, HTTPNetworkRegistrationService(compatibilityZoneURL))
.buildKeystore()
return doneFuture(Unit)
NetworkRegistrationHelper(configuration, HTTPNetworkRegistrationService(compatibilityZoneURL)).buildKeystore()
doneFuture(Unit)
} else {
return startNodeForRegistration(config)
startOutOfProcessNodeRegistration(config, configuration)
}
}
@ -872,18 +896,18 @@ class DriverDSL(
ServiceIdentityGenerator.generateToDisk(
dirs = listOf(baseDirectory(spec.name)),
serviceName = spec.name,
rootCertertificate = rootCertificate,
serviceId = "identity"
serviceId = "identity",
customRootCert = compatibilityZone?.rootCert
)
} else {
ServiceIdentityGenerator.generateToDisk(
dirs = generateNodeNames(spec).map { baseDirectory(it) },
serviceName = spec.name,
rootCertertificate = rootCertificate,
serviceId = NotaryService.constructId(
validating = spec.validating,
raft = spec.cluster is ClusterSpec.Raft
)
),
customRootCert = compatibilityZone?.rootCert
)
}
NotaryInfo(identity, spec.validating)
@ -1008,16 +1032,12 @@ class DriverDSL(
return future
}
private fun startNodeForRegistration(config: Config): CordaFuture<Unit> {
val maximumHeapSize = "200m"
val configuration = config.parseAsNodeConfiguration()
configuration.baseDirectory.createDirectories()
private fun startOutOfProcessNodeRegistration(config: Config, configuration: NodeConfiguration): CordaFuture<Unit> {
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val process = startOutOfProcessNode(configuration, config, quasarJarPath, debugPort,
systemProperties, cordappPackages, maximumHeapSize, initialRegistration = true)
systemProperties, cordappPackages, "200m", initialRegistration = true)
return poll(executorService, "process exit") {
return poll(executorService, "node registration (${configuration.myLegalName})") {
if (process.isAlive) null else Unit
}
}
@ -1030,7 +1050,7 @@ class DriverDSL(
val baseDirectory = configuration.baseDirectory.createDirectories()
// Distribute node info file using file copier when network map service URL (compatibilityZoneURL) is null.
// TODO: need to implement the same in cordformation?
val nodeInfoFilesCopier = if (compatibilityZoneURL == null) nodeInfoFilesCopier else null
val nodeInfoFilesCopier = if (compatibilityZone == null) nodeInfoFilesCopier else null
nodeInfoFilesCopier?.addConfig(baseDirectory)
networkParameters!!.install(baseDirectory)
@ -1068,7 +1088,7 @@ class DriverDSL(
}
val p2pReadyFuture = addressMustBeBoundFuture(executorService, configuration.p2pAddress, process)
return p2pReadyFuture.flatMap {
val processDeathFuture = poll(executorService, "process death") {
val processDeathFuture = poll(executorService, "process death while waiting for RPC (${configuration.myLegalName})") {
if (process.isAlive) null else process
}
establishRpc(configuration, processDeathFuture).flatMap { rpc ->

View File

@ -47,9 +47,7 @@ import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy
import org.apache.activemq.artemis.core.settings.impl.AddressSettings
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3
import org.bouncycastle.cert.X509CertificateHolder
import java.lang.reflect.Method
import java.net.URL
import java.nio.file.Path
import java.nio.file.Paths
import java.util.*
@ -225,6 +223,7 @@ val fakeNodeLegalName = CordaX500Name(organisation = "Not:a:real:name", locality
// Use a global pool so that we can run RPC tests in parallel
private val globalPortAllocation = PortAllocation.Incremental(10000)
private val globalDebugPortAllocation = PortAllocation.Incremental(5005)
fun <A> rpcDriver(
isDebug: Boolean = false,
driverDirectory: Path = Paths.get("build", getTimestampAsDirectoryName()),
@ -237,8 +236,6 @@ fun <A> rpcDriver(
extraCordappPackagesToScan: List<String> = emptyList(),
notarySpecs: List<NotarySpec> = emptyList(),
externalTrace: Trace? = null,
compatibilityZoneURL: URL? = null,
rootCertificate: X509CertificateHolder? = null,
dsl: RPCDriverExposedDSLInterface.() -> A
) = genericDriver(
driverDsl = RPCDriverDSL(
@ -253,8 +250,7 @@ fun <A> rpcDriver(
waitForNodesToFinish = waitForNodesToFinish,
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
compatibilityZone = null
), externalTrace
),
coerce = { it },

View File

@ -6,9 +6,8 @@ import net.corda.cordform.CordformDefinition
import net.corda.cordform.CordformNode
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.testing.driver.DriverDSL
import net.corda.testing.driver.PortAllocation
import net.corda.testing.driver.driver
import net.corda.testing.driver.internalDriver
fun CordformDefinition.clean() {
System.err.println("Deleting: $nodesDirectory")
@ -39,7 +38,7 @@ private fun CordformDefinition.runNodes(waitForAllNodesToFinish: Boolean, block:
.flatMap { listOf(it.p2pAddress, it.rpcAddress, it.webAddress) }
.mapNotNull { address -> address?.let { NetworkHostAndPort.parse(it).port } }
.max()!!
driver(
internalDriver(
isDebug = true,
driverDirectory = nodesDirectory,
extraCordappPackagesToScan = cordappPackages,
@ -50,7 +49,7 @@ private fun CordformDefinition.runNodes(waitForAllNodesToFinish: Boolean, block:
waitForAllNodesToFinish = waitForAllNodesToFinish
) {
setup(this)
(this as DriverDSL).startCordformNodes(nodes).getOrThrow() // Only proceed once everything is up and running
startCordformNodes(nodes).getOrThrow() // Only proceed once everything is up and running
println("All nodes and webservers are ready...")
block()
}

View File

@ -19,9 +19,9 @@ import net.corda.node.services.config.configureDevKeyAndTrustStores
import net.corda.nodeapi.ArtemisTcpTransport
import net.corda.nodeapi.ConnectionDirection
import net.corda.nodeapi.VerifierApi
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER
import net.corda.nodeapi.internal.config.NodeSSLConfiguration
import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_USER
import net.corda.testing.driver.*
import net.corda.testing.internal.ProcessUtilities
import net.corda.testing.node.NotarySpec
@ -37,8 +37,6 @@ import org.apache.activemq.artemis.core.security.CheckType
import org.apache.activemq.artemis.core.security.Role
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager
import org.bouncycastle.cert.X509CertificateHolder
import java.net.URL
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.ConcurrentHashMap
@ -87,8 +85,6 @@ fun <A> verifierDriver(
waitForNodesToFinish: Boolean = false,
extraCordappPackagesToScan: List<String> = emptyList(),
notarySpecs: List<NotarySpec> = emptyList(),
compatibilityZoneURL: URL? = null,
rootCertificate: X509CertificateHolder? = null,
dsl: VerifierExposedDSLInterface.() -> A
) = genericDriver(
driverDsl = VerifierDriverDSL(
@ -103,8 +99,7 @@ fun <A> verifierDriver(
waitForNodesToFinish = waitForNodesToFinish,
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
compatibilityZone = null
)
),
coerce = { it },