ENT-1125 bootstrap root certificate (#2151)

* ENT-1125 make nodes check that the returned signed certificate from Doorman has the expected root
This commit is contained in:
Alberto Arri 2017-12-04 12:53:22 +00:00 committed by GitHub
parent d5e3f28303
commit acd2281b20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 271 additions and 53 deletions

View File

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

View File

@ -9,8 +9,10 @@ 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
object ServiceIdentityGenerator {
private val log = LoggerFactory.getLogger(javaClass)
@ -22,18 +24,25 @@ 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.
*/
fun generateToDisk(dirs: List<Path>,
serviceName: CordaX500Name,
serviceId: String,
threshold: Int = 1): Party {
threshold: Int = 1,
rootCertertificate: X509CertificateHolder? = 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 = caKeyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)
val rootCert: Certificate = if (rootCertertificate != null) {
rootCertertificate.cert
} else {
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

@ -313,6 +313,11 @@ class X509CertificateFactory {
fun generateCertificate(input: InputStream): X509Certificate {
return delegate.generateCertificate(input) as X509Certificate
}
// TODO migrate calls to [CertificateFactory#generateCertPath] to call this instead.
fun generateCertPath(vararg certificates: Certificate): CertPath {
return delegate.generateCertPath(certificates.asList())
}
}
enum class CertificateType(val keyUsage: KeyUsage, vararg val purposes: KeyPurposeId, val isCA: Boolean) {

View File

@ -0,0 +1,182 @@
package net.corda.node.utilities.registration
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.minutes
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
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.PortAllocation
import net.corda.testing.driver.driver
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
import org.junit.Before
import org.junit.Test
import java.io.ByteArrayOutputStream
import java.io.InputStream
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]
*/
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, "")
@Before
fun startServer() {
server = NetworkMapServer(1.minutes, portAllocation.nextHostAndPort(), handler)
val (host, port) = server.start()
this.host = host
this.port = port
}
@After
fun stopServer() {
server.close()
}
@Test
fun `node registration correct root cert`() {
driver(portAllocation = portAllocation,
compatibilityZoneURL = compatibilityZoneUrl,
startNodesInProcess = true,
rootCertificate = rootCert
) {
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)
}
}
@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)
}
}
}
/**
* 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
@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()
}
@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())
}
}
// 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()
}
}
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)
}

View File

@ -12,6 +12,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
import org.bouncycastle.openssl.jcajce.JcaPEMWriter
import org.bouncycastle.util.io.pem.PemObject
import java.io.StringWriter
import java.nio.file.Path
import java.security.KeyPair
import java.security.KeyStore
import java.security.cert.Certificate
@ -75,10 +76,15 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
caKeyStore.addOrReplaceKey(CORDA_CLIENT_CA, keyPair.private, privateKeyPassword.toCharArray(), certificates)
caKeyStore.deleteEntry(SELF_SIGNED_PRIVATE_KEY)
caKeyStore.save(config.nodeKeystore, keystorePassword)
// Check the root certificate.
val returnedRootCa = certificates.last()
checkReturnedRootCaMatchesExpectedCa(returnedRootCa)
// Save root certificates to trust store.
val trustStore = loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword)
// Assumes certificate chain always starts with client certificate and end with root certificate.
trustStore.addOrReplaceCertificate(CORDA_ROOT_CA, certificates.last())
trustStore.addOrReplaceCertificate(CORDA_ROOT_CA, returnedRootCa)
trustStore.save(config.trustStoreFile, config.trustStorePassword)
println("Node private key and certificate stored in ${config.nodeKeystore}.")
@ -98,6 +104,17 @@ 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.
*/
private fun checkReturnedRootCaMatchesExpectedCa(returnedRootCa: Certificate) {
val expected = X509Utilities.loadCertificateFromPEMFile(config.rootCaCertFile).cert
if (expected != returnedRootCa) {
throw WrongRootCaCertificateException(expected, returnedRootCa, config.rootCaCertFile)
}
}
/**
* Poll Certificate Signing Server for approved certificate,
* enter a slow polling loop if server return null.
@ -151,3 +168,17 @@ 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):
Exception("""
The Root CA returned back from the registration process does not match the expected Root CA
expected: $expected
actual: $actual
the expected certificate is stored in: $expectedFilePath
""".trimMargin())

View File

@ -46,6 +46,9 @@ class NetworkRegistrationHelperTest {
baseDirectory = tempFolder.root.toPath(),
myLegalName = ALICE.name)
config.rootCaCertFile.parent.createDirectories()
X509Utilities.saveCertificateAsPEMFile(certs.last().toX509CertHolder(), config.rootCaCertFile)
assertFalse(config.nodeKeystore.exists())
assertFalse(config.sslKeystore.exists())
assertFalse(config.trustStoreFile.exists())

View File

@ -5,25 +5,17 @@ import net.corda.core.internal.div
import net.corda.core.internal.list
import net.corda.core.internal.readLines
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.minutes
import net.corda.core.utilities.seconds
import net.corda.node.internal.NodeStartup
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_REGULATOR
import net.corda.testing.common.internal.ProjectStructure.projectRootDir
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.network.NetworkMapServer
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import java.net.URL
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import javax.ws.rs.GET
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.core.Response
import javax.ws.rs.core.Response.ok
class DriverTests {
companion object {
@ -61,22 +53,6 @@ class DriverTests {
nodeMustBeDown(nodeHandle)
}
@Test
fun `node registration`() {
val handler = RegistrationHandler()
NetworkMapServer(1.seconds, portAllocation.nextHostAndPort(), handler).use {
val (host, port) = it.start()
driver(portAllocation = portAllocation, compatibilityZoneURL = URL("http://$host:$port")) {
// Wait for the node to have started.
startNode(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/reply")
}
@Test
fun `debug mode enables debug logging level`() {
@ -106,20 +82,3 @@ class DriverTests {
assertThat(baseDirectory / "process-id").doesNotExist()
}
}
@Path("certificate")
class RegistrationHandler {
val requests = mutableListOf<String>()
@POST
fun registration(): Response {
requests += "/certificate"
return ok("reply").build()
}
@GET
@Path("reply")
fun reply(): Response {
requests += "/certificate/reply"
return ok().build()
}
}

View File

@ -78,6 +78,7 @@ fun testNodeConfiguration(
doCallRealMethod().whenever(it).trustStoreFile
doCallRealMethod().whenever(it).sslKeystore
doCallRealMethod().whenever(it).nodeKeystore
doCallRealMethod().whenever(it).rootCaCertFile
}
}

View File

@ -41,6 +41,7 @@ import net.corda.nodeapi.config.parseAs
import net.corda.nodeapi.config.toConfig
import net.corda.nodeapi.internal.NotaryInfo
import net.corda.nodeapi.internal.addShutdownHook
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.testing.*
import net.corda.nodeapi.internal.NetworkParametersCopier
import net.corda.testing.common.internal.testNetworkParameters
@ -51,6 +52,7 @@ 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
@ -343,9 +345,11 @@ data class NodeParameters(
* 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,
@ -360,6 +364,7 @@ fun <A> driver(
notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs,
extraCordappPackagesToScan: List<String> = defaultParameters.extraCordappPackagesToScan,
compatibilityZoneURL: URL? = defaultParameters.compatibilityZoneURL,
rootCertificate: X509CertificateHolder? = defaultParameters.rootCertificate,
dsl: DriverDSLExposedInterface.() -> A
): A {
return genericDriver(
@ -374,7 +379,8 @@ fun <A> driver(
waitForNodesToFinish = waitForAllNodesToFinish,
notarySpecs = notarySpecs,
extraCordappPackagesToScan = extraCordappPackagesToScan,
compatibilityZoneURL = compatibilityZoneURL
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
),
coerce = { it },
dsl = dsl,
@ -410,7 +416,8 @@ data class DriverParameters(
val waitForNodesToFinish: Boolean = false,
val notarySpecs: List<NotarySpec> = listOf(NotarySpec(DUMMY_NOTARY.name)),
val extraCordappPackagesToScan: List<String> = emptyList(),
val compatibilityZoneURL: URL? = null
val compatibilityZoneURL: URL? = null,
val rootCertificate: X509CertificateHolder? = null
) {
fun setIsDebug(isDebug: Boolean) = copy(isDebug = isDebug)
fun setDriverDirectory(driverDirectory: Path) = copy(driverDirectory = driverDirectory)
@ -421,8 +428,10 @@ data class DriverParameters(
fun setInitialiseSerialization(initialiseSerialization: Boolean) = copy(initialiseSerialization = initialiseSerialization)
fun setStartNodesInProcess(startNodesInProcess: Boolean) = copy(startNodesInProcess = startNodesInProcess)
fun setTerminateNodesOnShutdown(terminateNodesOnShutdown: Boolean) = copy(waitForNodesToFinish = terminateNodesOnShutdown)
fun setExtraCordappPackagesToScan(extraCordappPackagesToScan: List<String>) = copy(extraCordappPackagesToScan = extraCordappPackagesToScan)
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)
}
/**
@ -476,6 +485,7 @@ fun <DI : DriverDSLExposedInterface, D : DriverDSLInternalInterface, A> genericD
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
): A {
@ -492,7 +502,8 @@ fun <DI : DriverDSLExposedInterface, D : DriverDSLInternalInterface, A> genericD
waitForNodesToFinish = waitForNodesToFinish,
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
compatibilityZoneURL = compatibilityZoneURL
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
)
)
val shutdownHook = addShutdownHook(driverDsl::shutdown)
@ -599,7 +610,8 @@ class DriverDSL(
val waitForNodesToFinish: Boolean,
extraCordappPackagesToScan: List<String>,
val notarySpecs: List<NotarySpec>,
val compatibilityZoneURL: URL?
val compatibilityZoneURL: URL?,
val rootCertificate: X509CertificateHolder?
) : DriverDSLInternalInterface {
private var _executorService: ScheduledExecutorService? = null
val executorService get() = _executorService!!
@ -711,6 +723,11 @@ 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> {
val config = ConfigHelper.loadConfig(
baseDirectory = baseDirectory(providedName),
@ -720,10 +737,12 @@ class DriverDSL(
"compatibilityZoneURL" to compatibilityZoneURL.toString(),
"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) {
// This is a bit cheating, we're not starting a full node, we're just calling the code nodes call
// when registering.
val configuration = config.parseAsNodeConfiguration()
NetworkRegistrationHelper(configuration, HTTPNetworkRegistrationService(compatibilityZoneURL))
.buildKeystore()
return doneFuture(Unit)
@ -857,12 +876,14 @@ class DriverDSL(
ServiceIdentityGenerator.generateToDisk(
dirs = listOf(baseDirectory(spec.name)),
serviceName = spec.name,
rootCertertificate = rootCertificate,
serviceId = "identity"
)
} 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

View File

@ -47,6 +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
@ -237,6 +238,7 @@ fun <A> rpcDriver(
notarySpecs: List<NotarySpec> = emptyList(),
externalTrace: Trace? = null,
compatibilityZoneURL: URL? = null,
rootCertificate: X509CertificateHolder? = null,
dsl: RPCDriverExposedDSLInterface.() -> A
) = genericDriver(
driverDsl = RPCDriverDSL(
@ -251,7 +253,8 @@ fun <A> rpcDriver(
waitForNodesToFinish = waitForNodesToFinish,
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
compatibilityZoneURL = compatibilityZoneURL
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
), externalTrace
),
coerce = { it },

View File

@ -37,6 +37,7 @@ 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
@ -87,6 +88,7 @@ fun <A> verifierDriver(
extraCordappPackagesToScan: List<String> = emptyList(),
notarySpecs: List<NotarySpec> = emptyList(),
compatibilityZoneURL: URL? = null,
rootCertificate: X509CertificateHolder? = null,
dsl: VerifierExposedDSLInterface.() -> A
) = genericDriver(
driverDsl = VerifierDriverDSL(
@ -101,7 +103,8 @@ fun <A> verifierDriver(
waitForNodesToFinish = waitForNodesToFinish,
extraCordappPackagesToScan = extraCordappPackagesToScan,
notarySpecs = notarySpecs,
compatibilityZoneURL = compatibilityZoneURL
compatibilityZoneURL = compatibilityZoneURL,
rootCertificate = rootCertificate
)
),
coerce = { it },