diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ServiceIdentityGenerator.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ServiceIdentityGenerator.kt index 44d420d893..8b88df05ec 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/ServiceIdentityGenerator.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/ServiceIdentityGenerator.kt @@ -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, 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) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/SSLConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/SSLConfiguration.kt index dbe587373c..b4c8534b93 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/SSLConfiguration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/config/SSLConfiguration.kt @@ -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" } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt index dfb6d17e81..d5d40b7a3c 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt @@ -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 } /** diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt index 7ed2ff6527..31bc5505ae 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt @@ -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) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapClientTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapClientTest.kt index d82386ab5b..de53694fdf 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapClientTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/network/NetworkMapClientTest.kt @@ -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) } } diff --git a/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperDriverTest.kt b/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperDriverTest.kt index fb5a59fe14..4e20a5c710 100644 --- a/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperDriverTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperDriverTest.kt @@ -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() - lateinit var certificationRequest: JcaPKCS10CertificationRequest +class RegistrationHandler(private val rootCertAndKeyPair: CertificateAndKeyPair) { + private val certPaths = HashMap() + val idsPolled = HashSet() @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): 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): 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): 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): Pair { + 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) + } } diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index 83edb78fbe..d16797e85b 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -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 diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt similarity index 59% rename from node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt rename to node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt index 330b32fbc3..97a9e2b818 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelperTest.kt @@ -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().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() + + 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().also { + doReturn(requestId).whenever(it).submitRequest(any()) + doReturn(response).whenever(it).retrieveCertificates(eq(requestId)) + } + } } diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt index e9fa30cffe..6f9ea9daa5 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt @@ -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() } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt index be2c472d16..a27fbab11c 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt @@ -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 = defaultParameters.customOverrides, startInSameProcess: Boolean? = defaultParameters.startInSameProcess, - maximumHeapSize: String = defaultParameters.maximumHeapSize, - initialRegistration: Boolean = defaultParameters.initialRegistration): CordaFuture + maximumHeapSize: String = defaultParameters.maximumHeapSize + ): CordaFuture /** @@ -301,8 +301,7 @@ data class NodeParameters( val verifierType: VerifierType = VerifierType.InMemory, val customOverrides: Map = 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) = 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 driver( defaultParameters: DriverParameters = DriverParameters(), isDebug: Boolean = defaultParameters.isDebug, @@ -359,8 +354,6 @@ fun driver( waitForAllNodesToFinish: Boolean = defaultParameters.waitForNodesToFinish, notarySpecs: List = defaultParameters.notarySpecs, extraCordappPackagesToScan: List = defaultParameters.extraCordappPackagesToScan, - compatibilityZoneURL: URL? = defaultParameters.compatibilityZoneURL, - rootCertificate: X509CertificateHolder? = defaultParameters.rootCertificate, dsl: DriverDSLExposedInterface.() -> A ): A { return genericDriver( @@ -375,8 +368,51 @@ fun 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 internalDriver( + isDebug: Boolean = DriverParameters().isDebug, + driverDirectory: Path = DriverParameters().driverDirectory, + portAllocation: PortAllocation = DriverParameters().portAllocation, + debugPortAllocation: PortAllocation = DriverParameters().debugPortAllocation, + systemProperties: Map = DriverParameters().systemProperties, + useTestClock: Boolean = DriverParameters().useTestClock, + initialiseSerialization: Boolean = DriverParameters().initialiseSerialization, + startNodesInProcess: Boolean = DriverParameters().startNodesInProcess, + waitForAllNodesToFinish: Boolean = DriverParameters().waitForNodesToFinish, + notarySpecs: List = DriverParameters().notarySpecs, + extraCordappPackagesToScan: List = 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 = listOf(NotarySpec(DUMMY_NOTARY.name)), - val extraCordappPackagesToScan: List = emptyList(), - val compatibilityZoneURL: URL? = null, - val rootCertificate: X509CertificateHolder? = null + val extraCordappPackagesToScan: List = 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) = copy(notarySpecs = notarySpecs) fun setExtraCordappPackagesToScan(extraCordappPackagesToScan: List) = copy(extraCordappPackagesToScan = extraCordappPackagesToScan) - fun setCompatibilityZoneURL(compatibilityZoneURL: URL?) = copy(compatibilityZoneURL = compatibilityZoneURL) - fun setRootCertificate(rootCertificate: X509CertificateHolder?) = copy(rootCertificate = rootCertificate) } /** @@ -480,10 +512,9 @@ fun genericD startNodesInProcess: Boolean = defaultParameters.startNodesInProcess, notarySpecs: List, extraCordappPackagesToScan: List = 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 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, val notarySpecs: List, - 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, startInSameProcess: Boolean?, - maximumHeapSize: String, - initialRegistration: Boolean + maximumHeapSize: String ): CordaFuture { 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 { + private fun nodeRegistration(providedName: CordaX500Name, rootCert: X509Certificate, compatibilityZoneURL: URL): CordaFuture { + 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 { - val maximumHeapSize = "200m" - val configuration = config.parseAsNodeConfiguration() - configuration.baseDirectory.createDirectories() - + private fun startOutOfProcessNodeRegistration(config: Config, configuration: NodeConfiguration): CordaFuture { 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 -> diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt index 5dab84146c..acb0532170 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/RPCDriver.kt @@ -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 rpcDriver( isDebug: Boolean = false, driverDirectory: Path = Paths.get("build", getTimestampAsDirectoryName()), @@ -237,8 +236,6 @@ fun rpcDriver( extraCordappPackagesToScan: List = emptyList(), notarySpecs: List = emptyList(), externalTrace: Trace? = null, - compatibilityZoneURL: URL? = null, - rootCertificate: X509CertificateHolder? = null, dsl: RPCDriverExposedDSLInterface.() -> A ) = genericDriver( driverDsl = RPCDriverDSL( @@ -253,8 +250,7 @@ fun rpcDriver( waitForNodesToFinish = waitForNodesToFinish, extraCordappPackagesToScan = extraCordappPackagesToScan, notarySpecs = notarySpecs, - compatibilityZoneURL = compatibilityZoneURL, - rootCertificate = rootCertificate + compatibilityZone = null ), externalTrace ), coerce = { it }, diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/DemoRunner.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/DemoRunner.kt index 2d431799be..474e936c21 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/DemoRunner.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/internal/demorun/DemoRunner.kt @@ -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() } diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt index ad93ad819f..5e35b75ec3 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt @@ -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 verifierDriver( waitForNodesToFinish: Boolean = false, extraCordappPackagesToScan: List = emptyList(), notarySpecs: List = emptyList(), - compatibilityZoneURL: URL? = null, - rootCertificate: X509CertificateHolder? = null, dsl: VerifierExposedDSLInterface.() -> A ) = genericDriver( driverDsl = VerifierDriverDSL( @@ -103,8 +99,7 @@ fun verifierDriver( waitForNodesToFinish = waitForNodesToFinish, extraCordappPackagesToScan = extraCordappPackagesToScan, notarySpecs = notarySpecs, - compatibilityZoneURL = compatibilityZoneURL, - rootCertificate = rootCertificate + compatibilityZone = null ) ), coerce = { it },