From 8376f29cac2af77572885e3360c07572c2980520 Mon Sep 17 00:00:00 2001 From: Patrick Kuo Date: Mon, 18 Sep 2017 10:20:59 +0100 Subject: [PATCH] Added end to end integration test for doorman. (#38) * * added integration test, using corda's network registration helper with doorman. * fix up after rebase --- .idea/compiler.xml | 5 +- doorman/build.gradle | 24 +++++ .../corda/doorman/DoormanIntegrationTest.kt | 91 +++++++++++++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 doorman/src/integration-test/kotlin/com/r3/corda/doorman/DoormanIntegrationTest.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 4edce38213..9e73df7661 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -28,6 +28,7 @@ + @@ -38,10 +39,10 @@ - - + + diff --git a/doorman/build.gradle b/doorman/build.gradle index d5d5f6a61f..2ddaa94d26 100644 --- a/doorman/build.gradle +++ b/doorman/build.gradle @@ -21,6 +21,29 @@ repositories { } } +configurations{ + integrationTestCompile.extendsFrom testCompile + integrationTestRuntime.extendsFrom testRuntime +} + +sourceSets{ + integrationTest { + kotlin { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/kotlin') + } + java { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/java') + } + resources { + srcDir file('src/integration-test/resources') + } + } +} + task buildDoormanJAR(type: FatCapsule, dependsOn: 'jar') { group = 'build' applicationClass 'com.r3.corda.doorman.MainKt' @@ -44,6 +67,7 @@ dependencies { compile "net.corda:corda-node:$corda_dependency_version" compile "net.corda:corda-node-api:$corda_dependency_version" testCompile "net.corda:corda-test-utils:$corda_dependency_version" + testCompile "net.corda:corda-node-driver:$corda_dependency_version" // Log4J: logging framework (with SLF4J bindings) compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" diff --git a/doorman/src/integration-test/kotlin/com/r3/corda/doorman/DoormanIntegrationTest.kt b/doorman/src/integration-test/kotlin/com/r3/corda/doorman/DoormanIntegrationTest.kt new file mode 100644 index 0000000000..1a3dc2280f --- /dev/null +++ b/doorman/src/integration-test/kotlin/com/r3/corda/doorman/DoormanIntegrationTest.kt @@ -0,0 +1,91 @@ +package com.r3.corda.doorman + +import com.google.common.net.HostAndPort +import com.nhaarman.mockito_kotlin.whenever +import com.r3.corda.doorman.persistence.CertificationRequestStorage +import com.r3.corda.doorman.persistence.DBCertificateRequestStorage +import com.r3.corda.doorman.persistence.DoormanSchemaService +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.SecureHash +import net.corda.core.identity.CordaX500Name +import net.corda.core.utilities.* +import net.corda.node.utilities.* +import net.corda.node.utilities.registration.HTTPNetworkRegistrationService +import net.corda.node.utilities.registration.NetworkRegistrationHelper +import net.corda.testing.ALICE +import net.corda.testing.testNodeConfiguration +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import java.net.URL +import java.util.* +import kotlin.test.assertEquals + +class DoormanIntegrationTest { + @Rule + @JvmField + val tempFolder = TemporaryFolder() + + @Test + fun `Network Registration With Doorman`() { + val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) + val rootCACert = X509Utilities.createSelfSignedCACertificate(getX500Name(CN = "Integration Test Corda Node Root CA", O = "R3 Ltd", L = "London", C = "GB"), rootCAKey) + val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) + val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, + getX500Name(CN = "Integration Test Corda Node Intermediate CA", L = "London", C = "GB", O = "R3 Ltd"), intermediateCAKey.public) + + val database = configureDatabase(makeTestDataSourceProperties(), null, { DoormanSchemaService() }, createIdentityService = { + // Identity service not needed doorman, corda persistence is not very generic. + throw UnsupportedOperationException() + }) + //Start doorman server + val doorman = DoormanServer(HostAndPort.fromParts("localhost", 0), CertificateAndKeyPair(intermediateCACert, intermediateCAKey), rootCACert.toX509Certificate(), + object : CertificationRequestStorage by DBCertificateRequestStorage(database) { + // The doorman is in approve all mode, returns all pending request id as approved request id. + override fun getApprovedRequestIds() = getPendingRequestIds() + }) + doorman.start() + + // Start Corda network registration. + val config = testNodeConfiguration( + baseDirectory = tempFolder.root.toPath(), + myLegalName = ALICE.name).also { + whenever(it.certificateSigningService).thenReturn(URL("http://localhost:${doorman.hostAndPort.port}")) + } + + NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.certificateSigningService)).buildKeystore() + + // Checks the keystore are created with the right certificates and keys. + assert(config.nodeKeystore.toFile().exists()) + assert(config.sslKeystore.toFile().exists()) + assert(config.trustStoreFile.toFile().exists()) + + loadKeyStore(config.nodeKeystore, config.keyStorePassword).apply { + assert(containsAlias(X509Utilities.CORDA_CLIENT_CA)) + assertEquals(ALICE.name.copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN).x500Name, getX509Certificate(X509Utilities.CORDA_CLIENT_CA).subject) + assertEquals(listOf(intermediateCACert.cert, rootCACert.cert), getCertificateChain(X509Utilities.CORDA_CLIENT_CA).drop(1).toList()) + } + + loadKeyStore(config.sslKeystore, config.keyStorePassword).apply { + assert(containsAlias(X509Utilities.CORDA_CLIENT_TLS)) + assertEquals(ALICE.name.x500Name, getX509Certificate(X509Utilities.CORDA_CLIENT_TLS).subject) + assertEquals(listOf(intermediateCACert.cert, rootCACert.cert), getCertificateChain(X509Utilities.CORDA_CLIENT_TLS).drop(2).toList()) + } + + loadKeyStore(config.trustStoreFile, config.trustStorePassword).apply { + assert(containsAlias(X509Utilities.CORDA_ROOT_CA)) + assertEquals(rootCACert.cert.subject, getX509Certificate(X509Utilities.CORDA_ROOT_CA).subject) + } + doorman.close() + } + + + private fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties { + val props = Properties() + props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource") + props.setProperty("dataSource.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE") + props.setProperty("dataSource.user", "sa") + props.setProperty("dataSource.password", "") + return props + } +} \ No newline at end of file