mirror of
https://github.com/corda/corda.git
synced 2024-12-20 05:28:21 +00:00
Enforce X.500 distinguished names in configuration
This commit is contained in:
parent
8c3b9ac589
commit
b64e7f51f6
@ -20,6 +20,7 @@ import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl
|
|||||||
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory
|
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory
|
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory
|
||||||
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ
|
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -74,7 +75,7 @@ abstract class AbstractClientRPCTest {
|
|||||||
override val users: List<User> get() = listOf(rpcUser)
|
override val users: List<User> get() = listOf(rpcUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dispatcher = object : RPCDispatcher(rpcImpl, userService, ALICE.name) {
|
val dispatcher = object : RPCDispatcher(rpcImpl, userService, X500Name(ALICE.name)) {
|
||||||
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
||||||
val msg = serverSession.createMessage(false).apply {
|
val msg = serverSession.createMessage(false).apply {
|
||||||
writeBodyBufferBytes(data.bytes)
|
writeBodyBufferBytes(data.bytes)
|
||||||
@ -99,4 +100,4 @@ abstract class AbstractClientRPCTest {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,8 @@ object X509Utilities {
|
|||||||
* Return a bogus X509 for dev purposes. Use [getX509Name] for something more real.
|
* Return a bogus X509 for dev purposes. Use [getX509Name] for something more real.
|
||||||
*/
|
*/
|
||||||
fun getDevX509Name(commonName: String): X500Name {
|
fun getDevX509Name(commonName: String): X500Name {
|
||||||
|
// Check that we haven't been accidentally given a full X500 distinguished name
|
||||||
|
require(!commonName.startsWith("CN=")) { "Provided common name must not start \"CN=\"" }
|
||||||
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
||||||
nameBuilder.addRDN(BCStyle.CN, commonName)
|
nameBuilder.addRDN(BCStyle.CN, commonName)
|
||||||
nameBuilder.addRDN(BCStyle.O, "R3")
|
nameBuilder.addRDN(BCStyle.O, "R3")
|
||||||
|
@ -4,6 +4,7 @@ import com.google.common.net.HostAndPort
|
|||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigUtil
|
import com.typesafe.config.ConfigUtil
|
||||||
import net.corda.core.noneOrSingle
|
import net.corda.core.noneOrSingle
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.net.Proxy
|
import java.net.Proxy
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@ -70,6 +71,7 @@ private fun Config.getSingleValue(path: String, type: KType): Any? {
|
|||||||
Path::class -> Paths.get(getString(path))
|
Path::class -> Paths.get(getString(path))
|
||||||
URL::class -> URL(getString(path))
|
URL::class -> URL(getString(path))
|
||||||
Properties::class -> getConfig(path).toProperties()
|
Properties::class -> getConfig(path).toProperties()
|
||||||
|
X500Name::class -> X500Name(getString(path))
|
||||||
else -> if (typeClass.java.isEnum) {
|
else -> if (typeClass.java.isEnum) {
|
||||||
parseEnum(typeClass.java, getString(path))
|
parseEnum(typeClass.java, getString(path))
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo
|
|||||||
import net.corda.core.readLines
|
import net.corda.core.readLines
|
||||||
import net.corda.core.utilities.DUMMY_BANK_A
|
import net.corda.core.utilities.DUMMY_BANK_A
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY
|
import net.corda.core.utilities.DUMMY_NOTARY
|
||||||
|
import net.corda.core.utilities.DUMMY_REGULATOR
|
||||||
import net.corda.node.LOGS_DIRECTORY_NAME
|
import net.corda.node.LOGS_DIRECTORY_NAME
|
||||||
import net.corda.node.services.api.RegulatorService
|
import net.corda.node.services.api.RegulatorService
|
||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
@ -42,7 +43,7 @@ class DriverTests {
|
|||||||
fun `simple node startup and shutdown`() {
|
fun `simple node startup and shutdown`() {
|
||||||
val handles = driver {
|
val handles = driver {
|
||||||
val notary = startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
val notary = startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||||
val regulator = startNode("CN=Regulator,O=R3,OU=corda,L=London,C=UK", setOf(ServiceInfo(RegulatorService.type)))
|
val regulator = startNode(DUMMY_REGULATOR.name, setOf(ServiceInfo(RegulatorService.type)))
|
||||||
listOf(nodeMustBeUp(notary), nodeMustBeUp(regulator))
|
listOf(nodeMustBeUp(notary), nodeMustBeUp(regulator))
|
||||||
}
|
}
|
||||||
handles.map { nodeMustBeDown(it) }
|
handles.map { nodeMustBeDown(it) }
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.services.messaging
|
|||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.services.DEFAULT_SESSION_ID
|
import net.corda.core.node.services.DEFAULT_SESSION_ID
|
||||||
@ -19,6 +20,7 @@ import net.corda.node.utilities.ServiceIdentityGenerator
|
|||||||
import net.corda.testing.freeLocalHostAndPort
|
import net.corda.testing.freeLocalHostAndPort
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
@ -27,6 +29,11 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
class P2PMessagingTest : NodeBasedTest() {
|
class P2PMessagingTest : NodeBasedTest() {
|
||||||
|
private companion object {
|
||||||
|
val DISTRIBUTED_SERVICE_NAME = X509Utilities.getDevX509Name("DistributedService")
|
||||||
|
val SERVICE_2_NAME = X509Utilities.getDevX509Name("Service Node 2")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `network map will work after restart`() {
|
fun `network map will work after restart`() {
|
||||||
val identities = listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
|
val identities = listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
|
||||||
@ -55,15 +62,14 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
// TODO Use a dummy distributed service
|
// TODO Use a dummy distributed service
|
||||||
@Test
|
@Test
|
||||||
fun `communicating with a distributed service which the network map node is part of`() {
|
fun `communicating with a distributed service which the network map node is part of`() {
|
||||||
val serviceName = "DistributedService"
|
|
||||||
|
|
||||||
val root = tempFolder.root.toPath()
|
val root = tempFolder.root.toPath()
|
||||||
ServiceIdentityGenerator.generateToDisk(
|
ServiceIdentityGenerator.generateToDisk(
|
||||||
listOf(root / DUMMY_MAP.name, root / "Service Node 2"),
|
listOf(root / DUMMY_MAP.name.toString(), root / SERVICE_2_NAME.toString()),
|
||||||
RaftValidatingNotaryService.type.id,
|
RaftValidatingNotaryService.type.id,
|
||||||
serviceName)
|
DISTRIBUTED_SERVICE_NAME)
|
||||||
|
|
||||||
val distributedService = ServiceInfo(RaftValidatingNotaryService.type, serviceName)
|
val distributedService = ServiceInfo(RaftValidatingNotaryService.type, DISTRIBUTED_SERVICE_NAME)
|
||||||
val notaryClusterAddress = freeLocalHostAndPort()
|
val notaryClusterAddress = freeLocalHostAndPort()
|
||||||
startNetworkMapNode(
|
startNetworkMapNode(
|
||||||
DUMMY_MAP.name,
|
DUMMY_MAP.name,
|
||||||
@ -71,7 +77,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
configOverrides = mapOf("notaryNodeAddress" to notaryClusterAddress.toString()))
|
configOverrides = mapOf("notaryNodeAddress" to notaryClusterAddress.toString()))
|
||||||
val (serviceNode2, alice) = Futures.allAsList(
|
val (serviceNode2, alice) = Futures.allAsList(
|
||||||
startNode(
|
startNode(
|
||||||
"Service Node 2",
|
SERVICE_2_NAME,
|
||||||
advertisedServices = setOf(distributedService),
|
advertisedServices = setOf(distributedService),
|
||||||
configOverrides = mapOf(
|
configOverrides = mapOf(
|
||||||
"notaryNodeAddress" to freeLocalHostAndPort().toString(),
|
"notaryNodeAddress" to freeLocalHostAndPort().toString(),
|
||||||
@ -79,14 +85,13 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
startNode(ALICE.name)
|
startNode(ALICE.name)
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
|
|
||||||
assertAllNodesAreUsed(listOf(networkMapNode, serviceNode2), serviceName, alice)
|
assertAllNodesAreUsed(listOf(networkMapNode, serviceNode2), DISTRIBUTED_SERVICE_NAME, alice)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `communicating with a distributed service which we're part of`() {
|
fun `communicating with a distributed service which we're part of`() {
|
||||||
val serviceName = "Distributed Service"
|
val distributedService = startNotaryCluster(DISTRIBUTED_SERVICE_NAME, 2).getOrThrow()
|
||||||
val distributedService = startNotaryCluster(serviceName, 2).getOrThrow()
|
assertAllNodesAreUsed(distributedService, DISTRIBUTED_SERVICE_NAME, distributedService[0])
|
||||||
assertAllNodesAreUsed(distributedService, serviceName, distributedService[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -183,13 +188,13 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
return Pair(firstRequestReceived, requestsReceived)
|
return Pair(firstRequestReceived, requestsReceived)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun assertAllNodesAreUsed(participatingServiceNodes: List<Node>, serviceName: String, originatingNode: Node) {
|
private fun assertAllNodesAreUsed(participatingServiceNodes: List<Node>, serviceName: X500Name, originatingNode: Node) {
|
||||||
// Setup each node in the distributed service to return back it's NodeInfo so that we can know which node is being used
|
// Setup each node in the distributed service to return back it's NodeInfo so that we can know which node is being used
|
||||||
participatingServiceNodes.forEach { node ->
|
participatingServiceNodes.forEach { node ->
|
||||||
node.respondWith(node.info)
|
node.respondWith(node.info)
|
||||||
}
|
}
|
||||||
val serviceAddress = originatingNode.services.networkMapCache.run {
|
val serviceAddress = originatingNode.services.networkMapCache.run {
|
||||||
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName)!!)!!)
|
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName.toString())!!)!!)
|
||||||
}
|
}
|
||||||
val participatingNodes = HashSet<Any>()
|
val participatingNodes = HashSet<Any>()
|
||||||
// Try several times so that we can be fairly sure that any node not participating is not due to Artemis' selection
|
// Try several times so that we can be fairly sure that any node not participating is not due to Artemis' selection
|
||||||
|
@ -2,12 +2,15 @@ package net.corda.services.messaging
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.random63BitValue
|
import net.corda.core.random63BitValue
|
||||||
import net.corda.core.seconds
|
import net.corda.core.seconds
|
||||||
import net.corda.core.utilities.BOB
|
import net.corda.core.utilities.BOB
|
||||||
|
import net.corda.core.utilities.DUMMY_BANK_A
|
||||||
|
import net.corda.core.utilities.DUMMY_BANK_B
|
||||||
import net.corda.node.internal.NetworkMapInfo
|
import net.corda.node.internal.NetworkMapInfo
|
||||||
import net.corda.node.services.config.configureWithDevSSLCertificate
|
import net.corda.node.services.config.configureWithDevSSLCertificate
|
||||||
import net.corda.node.services.messaging.sendRequest
|
import net.corda.node.services.messaging.sendRequest
|
||||||
@ -21,6 +24,7 @@ import net.corda.testing.node.NodeBasedTest
|
|||||||
import net.corda.testing.node.SimpleNode
|
import net.corda.testing.node.SimpleNode
|
||||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.concurrent.TimeoutException
|
import java.util.concurrent.TimeoutException
|
||||||
@ -42,9 +46,9 @@ class P2PSecurityTest : NodeBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `register with the network map service using a legal name different from the TLS CN`() {
|
fun `register with the network map service using a legal name different from the TLS CN`() {
|
||||||
startSimpleNode("CN=Attacker,O=R3,OU=corda,L=London,C=UK").use {
|
startSimpleNode(X500Name(DUMMY_BANK_A.name)).use {
|
||||||
// Register with the network map using a different legal name
|
// Register with the network map using a different legal name
|
||||||
val response = it.registerWithNetworkMap("CN=Legit Business,O=R3,OU=corda,L=London,C=UK")
|
val response = it.registerWithNetworkMap(X500Name(DUMMY_BANK_B.name))
|
||||||
// We don't expect a response because the network map's host verification will prevent a connection back
|
// We don't expect a response because the network map's host verification will prevent a connection back
|
||||||
// to the attacker as the TLS CN will not match the legal name it has just provided
|
// to the attacker as the TLS CN will not match the legal name it has just provided
|
||||||
assertThatExceptionOfType(TimeoutException::class.java).isThrownBy {
|
assertThatExceptionOfType(TimeoutException::class.java).isThrownBy {
|
||||||
@ -53,16 +57,16 @@ class P2PSecurityTest : NodeBasedTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startSimpleNode(legalName: String): SimpleNode {
|
private fun startSimpleNode(legalName: X500Name): SimpleNode {
|
||||||
val config = TestNodeConfiguration(
|
val config = TestNodeConfiguration(
|
||||||
baseDirectory = tempFolder.root.toPath() / legalName,
|
baseDirectory = tempFolder.root.toPath() / legalName.commonName,
|
||||||
myLegalName = legalName,
|
myLegalName = legalName,
|
||||||
networkMapService = NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name))
|
networkMapService = NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name))
|
||||||
config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name
|
config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name
|
||||||
return SimpleNode(config).apply { start() }
|
return SimpleNode(config).apply { start() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SimpleNode.registerWithNetworkMap(registrationName: String): ListenableFuture<NetworkMapService.RegistrationResponse> {
|
private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture<NetworkMapService.RegistrationResponse> {
|
||||||
val nodeInfo = NodeInfo(net.myAddress, Party(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion)
|
val nodeInfo = NodeInfo(net.myAddress, Party(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion)
|
||||||
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
||||||
val request = RegistrationRequest(registration.toWire(identity.private), net.myAddress)
|
val request = RegistrationRequest(registration.toWire(identity.private), net.myAddress)
|
||||||
|
@ -566,7 +566,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
// the legal name is actually validated in some way.
|
// the legal name is actually validated in some way.
|
||||||
val privKeyFile = dir / privateKeyFileName
|
val privKeyFile = dir / privateKeyFileName
|
||||||
val pubIdentityFile = dir / publicKeyFileName
|
val pubIdentityFile = dir / publicKeyFileName
|
||||||
val identityName = serviceName ?: configuration.myLegalName
|
val identityName = serviceName ?: configuration.myLegalName.toString()
|
||||||
|
|
||||||
val identityAndKey = if (!privKeyFile.exists()) {
|
val identityAndKey = if (!privKeyFile.exists()) {
|
||||||
log.info("Identity key not found, generating fresh key!")
|
log.info("Identity key not found, generating fresh key!")
|
||||||
|
@ -14,6 +14,7 @@ import net.corda.core.div
|
|||||||
import net.corda.core.exists
|
import net.corda.core.exists
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.nodeapi.config.SSLConfiguration
|
import net.corda.nodeapi.config.SSLConfiguration
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
object ConfigHelper {
|
object ConfigHelper {
|
||||||
@ -45,7 +46,7 @@ object ConfigHelper {
|
|||||||
*/
|
*/
|
||||||
fun NodeConfiguration.configureWithDevSSLCertificate() = configureDevKeyAndTrustStores(myLegalName)
|
fun NodeConfiguration.configureWithDevSSLCertificate() = configureDevKeyAndTrustStores(myLegalName)
|
||||||
|
|
||||||
fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: String) {
|
fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: X500Name) {
|
||||||
certificatesDirectory.createDirectories()
|
certificatesDirectory.createDirectories()
|
||||||
if (!trustStoreFile.exists()) {
|
if (!trustStoreFile.exists()) {
|
||||||
javaClass.classLoader.getResourceAsStream("net/corda/node/internal/certificates/cordatruststore.jks").copyTo(trustStoreFile)
|
javaClass.classLoader.getResourceAsStream("net/corda/node/internal/certificates/cordatruststore.jks").copyTo(trustStoreFile)
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.node.utilities.TestClock
|
|||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
import net.corda.nodeapi.config.OldConfig
|
import net.corda.nodeapi.config.OldConfig
|
||||||
import net.corda.nodeapi.config.SSLConfiguration
|
import net.corda.nodeapi.config.SSLConfiguration
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -20,7 +21,7 @@ import java.util.*
|
|||||||
interface NodeConfiguration : SSLConfiguration {
|
interface NodeConfiguration : SSLConfiguration {
|
||||||
val baseDirectory: Path
|
val baseDirectory: Path
|
||||||
override val certificatesDirectory: Path get() = baseDirectory / "certificates"
|
override val certificatesDirectory: Path get() = baseDirectory / "certificates"
|
||||||
val myLegalName: String
|
val myLegalName: X500Name
|
||||||
val networkMapService: NetworkMapInfo?
|
val networkMapService: NetworkMapInfo?
|
||||||
val minimumPlatformVersion: Int
|
val minimumPlatformVersion: Int
|
||||||
val nearestCity: String
|
val nearestCity: String
|
||||||
@ -41,7 +42,7 @@ data class FullNodeConfiguration(
|
|||||||
"This is a subsitution value which points to the baseDirectory and is manually added into the config before parsing",
|
"This is a subsitution value which points to the baseDirectory and is manually added into the config before parsing",
|
||||||
ReplaceWith("baseDirectory"))
|
ReplaceWith("baseDirectory"))
|
||||||
val basedir: Path,
|
val basedir: Path,
|
||||||
override val myLegalName: String,
|
override val myLegalName: X500Name,
|
||||||
override val nearestCity: String,
|
override val nearestCity: String,
|
||||||
override val emailAddress: String,
|
override val emailAddress: String,
|
||||||
override val keyStorePassword: String,
|
override val keyStorePassword: String,
|
||||||
|
@ -238,7 +238,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
.loadCertificateFromKeyStore(config.keyStoreFile, config.keyStorePassword, CORDA_CLIENT_CA)
|
.loadCertificateFromKeyStore(config.keyStoreFile, config.keyStorePassword, CORDA_CLIENT_CA)
|
||||||
val ourSubjectDN = X500Name(ourCertificate.subjectDN.name)
|
val ourSubjectDN = X500Name(ourCertificate.subjectDN.name)
|
||||||
// This is a sanity check and should not fail unless things have been misconfigured
|
// This is a sanity check and should not fail unless things have been misconfigured
|
||||||
require(ourSubjectDN.commonName == config.myLegalName) {
|
require(ourSubjectDN.commonName == config.myLegalName.commonName) {
|
||||||
"Legal name does not match with our subject CN: $ourSubjectDN"
|
"Legal name does not match with our subject CN: $ourSubjectDN"
|
||||||
}
|
}
|
||||||
val defaultCertPolicies = mapOf(
|
val defaultCertPolicies = mapOf(
|
||||||
@ -398,18 +398,18 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
private fun getBridgeName(queueName: String, hostAndPort: HostAndPort): String = "$queueName -> $hostAndPort"
|
private fun getBridgeName(queueName: String, hostAndPort: HostAndPort): String = "$queueName -> $hostAndPort"
|
||||||
|
|
||||||
// This is called on one of Artemis' background threads
|
// This is called on one of Artemis' background threads
|
||||||
internal fun hostVerificationFail(peerLegalName: String, expectedCommonName: String) {
|
internal fun hostVerificationFail(peerLegalName: X500Name, expectedLegalName: X500Name) {
|
||||||
log.error("Peer has wrong CN - expected $expectedCommonName but got $peerLegalName. This is either a fatal " +
|
log.error("Peer has wrong CN - expected $expectedLegalName but got $peerLegalName. This is either a fatal " +
|
||||||
"misconfiguration by the remote peer or an SSL man-in-the-middle attack!")
|
"misconfiguration by the remote peer or an SSL man-in-the-middle attack!")
|
||||||
if (expectedCommonName == config.networkMapService?.legalName) {
|
if (expectedLegalName.toString() == config.networkMapService?.legalName) {
|
||||||
// If the peer that failed host verification was the network map node then we're in big trouble and need to bail!
|
// If the peer that failed host verification was the network map node then we're in big trouble and need to bail!
|
||||||
_networkMapConnectionFuture!!.setException(IOException("${config.networkMapService} failed host verification check"))
|
_networkMapConnectionFuture!!.setException(IOException("${config.networkMapService} failed host verification check"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called on one of Artemis' background threads
|
// This is called on one of Artemis' background threads
|
||||||
internal fun onTcpConnection(peerLegalName: String) {
|
internal fun onTcpConnection(peerLegalName: X500Name) {
|
||||||
if (peerLegalName == config.networkMapService?.legalName) {
|
if (peerLegalName.toString() == config.networkMapService?.legalName) {
|
||||||
_networkMapConnectionFuture!!.set(Unit)
|
_networkMapConnectionFuture!!.set(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,7 +437,9 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
|||||||
protocolManager: ClientProtocolManager?) :
|
protocolManager: ClientProtocolManager?) :
|
||||||
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
|
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
|
||||||
private val server = configuration?.get(ArtemisMessagingServer::class.java.name) as? ArtemisMessagingServer
|
private val server = configuration?.get(ArtemisMessagingServer::class.java.name) as? ArtemisMessagingServer
|
||||||
private val expectedCommonName = configuration?.get(ArtemisTcpTransport.VERIFY_PEER_COMMON_NAME) as? String
|
private val expectedCommonName = (configuration?.get(ArtemisTcpTransport.VERIFY_PEER_COMMON_NAME) as? String)?.let {
|
||||||
|
X500Name(it)
|
||||||
|
}
|
||||||
|
|
||||||
override fun createConnection(): Connection? {
|
override fun createConnection(): Connection? {
|
||||||
val connection = super.createConnection() as NettyConnection?
|
val connection = super.createConnection() as NettyConnection?
|
||||||
@ -451,9 +453,8 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
|||||||
.peerPrincipal
|
.peerPrincipal
|
||||||
.name
|
.name
|
||||||
.let(::X500Name)
|
.let(::X500Name)
|
||||||
.commonName
|
|
||||||
// TODO Verify on the entire principle (subject)
|
// TODO Verify on the entire principle (subject)
|
||||||
if (peerLegalName != expectedCommonName) {
|
if (peerLegalName.commonName != expectedCommonName.commonName) {
|
||||||
connection.close()
|
connection.close()
|
||||||
server!!.hostVerificationFail(peerLegalName, expectedCommonName)
|
server!!.hostVerificationFail(peerLegalName, expectedCommonName)
|
||||||
return null // Artemis will keep trying to reconnect until it's told otherwise
|
return null // Artemis will keep trying to reconnect until it's told otherwise
|
||||||
|
@ -547,7 +547,7 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createRPCDispatcher(ops: RPCOps, userService: RPCUserService, nodeLegalName: String) =
|
private fun createRPCDispatcher(ops: RPCOps, userService: RPCUserService, nodeLegalName: X500Name): RPCDispatcher =
|
||||||
object : RPCDispatcher(ops, userService, nodeLegalName) {
|
object : RPCDispatcher(ops, userService, nodeLegalName) {
|
||||||
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
||||||
messagingExecutor.fetchFrom {
|
messagingExecutor.fetchFrom {
|
||||||
|
@ -37,7 +37,7 @@ import java.util.concurrent.atomic.AtomicInteger
|
|||||||
* are handled, this is probably the wrong system.
|
* are handled, this is probably the wrong system.
|
||||||
*/
|
*/
|
||||||
// TODO remove the nodeLegalName parameter once the webserver doesn't need special privileges
|
// TODO remove the nodeLegalName parameter once the webserver doesn't need special privileges
|
||||||
abstract class RPCDispatcher(val ops: RPCOps, val userService: RPCUserService, val nodeLegalName: String) {
|
abstract class RPCDispatcher(val ops: RPCOps, val userService: RPCUserService, val nodeLegalName: X500Name) {
|
||||||
// Throw an exception if there are overloaded methods
|
// Throw an exception if there are overloaded methods
|
||||||
private val methodTable = ops.javaClass.declaredMethods.groupBy { it.name }.mapValues { it.value.single() }
|
private val methodTable = ops.javaClass.declaredMethods.groupBy { it.name }.mapValues { it.value.single() }
|
||||||
|
|
||||||
@ -184,9 +184,14 @@ abstract class RPCDispatcher(val ops: RPCOps, val userService: RPCUserService, v
|
|||||||
val rpcUser = userService.getUser(validatedUser)
|
val rpcUser = userService.getUser(validatedUser)
|
||||||
if (rpcUser != null) {
|
if (rpcUser != null) {
|
||||||
return rpcUser
|
return rpcUser
|
||||||
} else if (X500Name(validatedUser).commonName == nodeLegalName) {
|
|
||||||
return nodeUser
|
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
|
if (X500Name(validatedUser) == nodeLegalName) {
|
||||||
|
return nodeUser
|
||||||
|
}
|
||||||
|
} catch (ex: IllegalArgumentException) {
|
||||||
|
// Just means the two can't be compared, treat as no match
|
||||||
|
}
|
||||||
throw IllegalArgumentException("Validated user '$validatedUser' is not an RPC user nor the NODE user")
|
throw IllegalArgumentException("Validated user '$validatedUser' is not an RPC user nor the NODE user")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ class NetworkRegistrationHelper(val config: NodeConfiguration, val certService:
|
|||||||
private fun submitOrResumeCertificateSigningRequest(keyPair: KeyPair): String {
|
private fun submitOrResumeCertificateSigningRequest(keyPair: KeyPair): String {
|
||||||
// Retrieve request id from file if exists, else post a request to server.
|
// Retrieve request id from file if exists, else post a request to server.
|
||||||
return if (!requestIdStore.exists()) {
|
return if (!requestIdStore.exists()) {
|
||||||
val request = X509Utilities.createCertificateSigningRequest(config.myLegalName, config.nearestCity, config.emailAddress, keyPair)
|
val request = X509Utilities.createCertificateSigningRequest(config.myLegalName, keyPair)
|
||||||
val writer = StringWriter()
|
val writer = StringWriter()
|
||||||
JcaPEMWriter(writer).use {
|
JcaPEMWriter(writer).use {
|
||||||
it.writeObject(PemObject("CERTIFICATE REQUEST", request.encoded))
|
it.writeObject(PemObject("CERTIFICATE REQUEST", request.encoded))
|
||||||
|
@ -34,7 +34,7 @@ class InteractiveShellTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val someCorpLegalName = MEGA_CORP.name
|
private val someCorpLegalName = MEGA_CORP.name
|
||||||
private val ids = InMemoryIdentityService().apply { registerIdentity(Party(MEGA_CORP.name, DUMMY_PUBKEY_1)) }
|
private val ids = InMemoryIdentityService().apply { registerIdentity(Party(someCorpLegalName, DUMMY_PUBKEY_1)) }
|
||||||
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())
|
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())
|
||||||
|
|
||||||
private fun check(input: String, expected: String) {
|
private fun check(input: String, expected: String) {
|
||||||
|
@ -4,6 +4,7 @@ import net.corda.core.utilities.ALICE
|
|||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
import net.corda.testing.testConfiguration
|
import net.corda.testing.testConfiguration
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ class FullNodeConfigurationTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `Artemis special characters not permitted in RPC usernames`() {
|
fun `Artemis special characters not permitted in RPC usernames`() {
|
||||||
fun configWithRPCUsername(username: String): FullNodeConfiguration {
|
fun configWithRPCUsername(username: String): FullNodeConfiguration {
|
||||||
return testConfiguration(Paths.get("."), ALICE.name, 0).copy(
|
return testConfiguration(Paths.get("."), X500Name(ALICE.name), 0).copy(
|
||||||
rpcUsers = listOf(User(username, "pass", emptySet())))
|
rpcUsers = listOf(User(username, "pass", emptySet())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import net.corda.testing.freeLocalHostAndPort
|
|||||||
import net.corda.testing.node.makeTestDataSourceProperties
|
import net.corda.testing.node.makeTestDataSourceProperties
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -71,7 +72,7 @@ class ArtemisMessagingTests {
|
|||||||
userService = RPCUserServiceImpl(emptyList())
|
userService = RPCUserServiceImpl(emptyList())
|
||||||
config = TestNodeConfiguration(
|
config = TestNodeConfiguration(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
myLegalName = ALICE.name,
|
myLegalName = X500Name(ALICE.name),
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||||
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())
|
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())
|
||||||
|
@ -39,7 +39,7 @@ class NetworkRegistrationHelperTest {
|
|||||||
|
|
||||||
val config = TestNodeConfiguration(
|
val config = TestNodeConfiguration(
|
||||||
baseDirectory = tempFolder.root.toPath(),
|
baseDirectory = tempFolder.root.toPath(),
|
||||||
myLegalName = ALICE.name,
|
myLegalName = X500Name(ALICE.name),
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
|
|
||||||
assertFalse(config.keyStoreFile.exists())
|
assertFalse(config.keyStoreFile.exists())
|
||||||
|
@ -72,8 +72,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
|
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = "CN=Bank $letter,O=Bank $letter,L=$city,C=$country",
|
myLegalName = X500Name("CN=Bank $letter,O=Bank $letter,L=$city,C=$country"),
|
||||||
nearestCity = city,
|
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||||
}
|
}
|
||||||
@ -95,8 +94,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
require(advertisedServices.containsType(NetworkMapService.type))
|
require(advertisedServices.containsType(NetworkMapService.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = DUMMY_MAP.name,
|
myLegalName = X500Name(DUMMY_MAP.name),
|
||||||
nearestCity = X500Name(DUMMY_MAP.name).location,
|
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {}
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {}
|
||||||
}
|
}
|
||||||
@ -109,8 +107,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
require(advertisedServices.containsType(SimpleNotaryService.type))
|
require(advertisedServices.containsType(SimpleNotaryService.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = DUMMY_NOTARY.name,
|
myLegalName = X500Name(DUMMY_NOTARY.name),
|
||||||
nearestCity = X500Name(DUMMY_NOTARY.name).location,
|
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||||
}
|
}
|
||||||
@ -118,7 +115,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
|
|
||||||
object RatesOracleFactory : MockNetwork.Factory {
|
object RatesOracleFactory : MockNetwork.Factory {
|
||||||
// TODO: Make a more realistic legal name
|
// TODO: Make a more realistic legal name
|
||||||
val RATES_SERVICE_NAME = "CN=Rates Service Provider,O=R3,OU=corda,L=Madrid,C=ES"
|
val RATES_SERVICE_NAME = X500Name("CN=Rates Service Provider,O=R3,OU=corda,L=Madrid,C=ES")
|
||||||
|
|
||||||
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
|
||||||
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||||
@ -127,7 +124,6 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = RATES_SERVICE_NAME,
|
myLegalName = RATES_SERVICE_NAME,
|
||||||
nearestCity = X500Name(RATES_SERVICE_NAME).location,
|
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
override fun start(): MockNetwork.MockNode {
|
override fun start(): MockNetwork.MockNode {
|
||||||
@ -149,8 +145,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
entropyRoot: BigInteger): MockNetwork.MockNode {
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = DUMMY_REGULATOR.name,
|
myLegalName = X500Name(DUMMY_REGULATOR.name),
|
||||||
nearestCity = X500Name(DUMMY_REGULATOR.name).location,
|
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
|
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
|
||||||
|
@ -127,7 +127,7 @@ class VisualiserViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun makeNodeWidget(forNode: MockNetwork.MockNode, type: String, label: String = "Bank of Bologna",
|
fun makeNodeWidget(forNode: MockNetwork.MockNode, type: String, label: X500Name = X500Name("CN=Bank of Bologna,OU=Corda QA Department,O=R3 CEV,L=Bologna,C=IT"),
|
||||||
nodeType: NetworkMapVisualiser.NodeType, index: Int): NodeWidget {
|
nodeType: NetworkMapVisualiser.NodeType, index: Int): NodeWidget {
|
||||||
fun emitRadarPulse(initialRadius: Double, targetRadius: Double, duration: Double): Pair<Circle, Animation> {
|
fun emitRadarPulse(initialRadius: Double, targetRadius: Double, duration: Double): Pair<Circle, Animation> {
|
||||||
val pulse = Circle(initialRadius).apply {
|
val pulse = Circle(initialRadius).apply {
|
||||||
@ -157,7 +157,7 @@ class VisualiserViewModel {
|
|||||||
view.root.children += longPulseOuterDot
|
view.root.children += longPulseOuterDot
|
||||||
view.root.children += innerDot
|
view.root.children += innerDot
|
||||||
|
|
||||||
val nameLabel = Label(label)
|
val nameLabel = Label(label.toString())
|
||||||
val nameLabelRect = StackPane(nameLabel).apply {
|
val nameLabelRect = StackPane(nameLabel).apply {
|
||||||
styleClass += "node-label"
|
styleClass += "node-label"
|
||||||
alignment = Pos.CENTER_RIGHT
|
alignment = Pos.CENTER_RIGHT
|
||||||
|
@ -28,6 +28,7 @@ import net.corda.testing.node.MockIdentityService
|
|||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.makeTestDataSourceProperties
|
import net.corda.testing.node.makeTestDataSourceProperties
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
@ -156,23 +157,24 @@ inline fun <reified P : FlowLogic<*>> AbstractNode.initiateSingleShotFlow(
|
|||||||
// TODO Replace this with testConfiguration
|
// TODO Replace this with testConfiguration
|
||||||
data class TestNodeConfiguration(
|
data class TestNodeConfiguration(
|
||||||
override val baseDirectory: Path,
|
override val baseDirectory: Path,
|
||||||
override val myLegalName: String,
|
override val myLegalName: X500Name,
|
||||||
override val networkMapService: NetworkMapInfo?,
|
override val networkMapService: NetworkMapInfo?,
|
||||||
override val minimumPlatformVersion: Int = 1,
|
override val minimumPlatformVersion: Int = 1,
|
||||||
override val keyStorePassword: String = "cordacadevpass",
|
override val keyStorePassword: String = "cordacadevpass",
|
||||||
override val trustStorePassword: String = "trustpass",
|
override val trustStorePassword: String = "trustpass",
|
||||||
override val rpcUsers: List<User> = emptyList(),
|
override val rpcUsers: List<User> = emptyList(),
|
||||||
override val dataSourceProperties: Properties = makeTestDataSourceProperties(myLegalName),
|
override val dataSourceProperties: Properties = makeTestDataSourceProperties(myLegalName),
|
||||||
override val nearestCity: String = "Null Island",
|
|
||||||
override val emailAddress: String = "",
|
override val emailAddress: String = "",
|
||||||
override val exportJMXto: String = "",
|
override val exportJMXto: String = "",
|
||||||
override val devMode: Boolean = true,
|
override val devMode: Boolean = true,
|
||||||
override val certificateSigningService: URL = URL("http://localhost"),
|
override val certificateSigningService: URL = URL("http://localhost"),
|
||||||
override val certificateChainCheckPolicies: List<CertChainPolicyConfig> = emptyList(),
|
override val certificateChainCheckPolicies: List<CertChainPolicyConfig> = emptyList(),
|
||||||
override val verifierType: VerifierType = VerifierType.InMemory,
|
override val verifierType: VerifierType = VerifierType.InMemory,
|
||||||
override val messageRedeliveryDelaySeconds: Int = 5) : NodeConfiguration
|
override val messageRedeliveryDelaySeconds: Int = 5) : NodeConfiguration {
|
||||||
|
override val nearestCity = myLegalName.getRDNs(BCStyle.L).single().typesAndValues.single().value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
fun testConfiguration(baseDirectory: Path, legalName: String, basePort: Int): FullNodeConfiguration {
|
fun testConfiguration(baseDirectory: Path, legalName: X500Name, basePort: Int): FullNodeConfiguration {
|
||||||
return FullNodeConfiguration(
|
return FullNodeConfiguration(
|
||||||
basedir = baseDirectory,
|
basedir = baseDirectory,
|
||||||
myLegalName = legalName,
|
myLegalName = legalName,
|
||||||
@ -198,7 +200,7 @@ fun testConfiguration(baseDirectory: Path, legalName: String, basePort: Int): Fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun configureTestSSL(legalName: String = "Mega Corp."): SSLConfiguration = object : SSLConfiguration {
|
fun configureTestSSL(legalName: X500Name = X500Name(MEGA_CORP.name)): SSLConfiguration = object : SSLConfiguration {
|
||||||
override val certificatesDirectory = Files.createTempDirectory("certs")
|
override val certificatesDirectory = Files.createTempDirectory("certs")
|
||||||
override val keyStorePassword: String get() = "cordacadevpass"
|
override val keyStorePassword: String get() = "cordacadevpass"
|
||||||
override val trustStorePassword: String get() = "trustpass"
|
override val trustStorePassword: String get() = "trustpass"
|
||||||
|
@ -7,12 +7,16 @@ import net.corda.nodeapi.ConnectionDirection
|
|||||||
import net.corda.nodeapi.config.SSLConfiguration
|
import net.corda.nodeapi.config.SSLConfiguration
|
||||||
import net.corda.testing.configureTestSSL
|
import net.corda.testing.configureTestSSL
|
||||||
import org.apache.activemq.artemis.api.core.client.*
|
import org.apache.activemq.artemis.api.core.client.*
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* As the name suggests this is a simple client for connecting to MQ brokers.
|
* As the name suggests this is a simple client for connecting to MQ brokers.
|
||||||
*/
|
*/
|
||||||
class SimpleMQClient(val target: HostAndPort,
|
class SimpleMQClient(val target: HostAndPort,
|
||||||
override val config: SSLConfiguration? = configureTestSSL("SimpleMQClient")) : ArtemisMessagingComponent() {
|
override val config: SSLConfiguration? = configureTestSSL(DEFAULT_MQ_LEGAL_NAME)) : ArtemisMessagingComponent() {
|
||||||
|
companion object {
|
||||||
|
val DEFAULT_MQ_LEGAL_NAME = X500Name("CN=SimpleMQClient,O=R3,OU=corda,L=London,C=UK")
|
||||||
|
}
|
||||||
lateinit var sessionFactory: ClientSessionFactory
|
lateinit var sessionFactory: ClientSessionFactory
|
||||||
lateinit var session: ClientSession
|
lateinit var session: ClientSession
|
||||||
lateinit var producer: ClientProducer
|
lateinit var producer: ClientProducer
|
||||||
|
@ -127,10 +127,10 @@ class InMemoryMessagingNetwork(
|
|||||||
id: Int,
|
id: Int,
|
||||||
executor: AffinityExecutor,
|
executor: AffinityExecutor,
|
||||||
advertisedServices: List<ServiceEntry>,
|
advertisedServices: List<ServiceEntry>,
|
||||||
description: String? = null,
|
description: X500Name? = null,
|
||||||
database: Database)
|
database: Database)
|
||||||
: MessagingServiceBuilder<InMemoryMessaging> {
|
: MessagingServiceBuilder<InMemoryMessaging> {
|
||||||
return Builder(manuallyPumped, PeerHandle(id, description ?: "In memory node $id"), advertisedServices.map(::ServiceHandle), executor, database = database)
|
return Builder(manuallyPumped, PeerHandle(id, description ?: X509Utilities.getDevX509Name("In memory node $id")), advertisedServices.map(::ServiceHandle), executor, database = database)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LatencyCalculator {
|
interface LatencyCalculator {
|
||||||
@ -198,8 +198,8 @@ class InMemoryMessagingNetwork(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class PeerHandle(val id: Int, val description: String) : SingleMessageRecipient {
|
data class PeerHandle(val id: Int, val description: X500Name) : SingleMessageRecipient {
|
||||||
override fun toString() = description
|
override fun toString() = description.toString()
|
||||||
override fun equals(other: Any?) = other is PeerHandle && other.id == id
|
override fun equals(other: Any?) = other is PeerHandle && other.id == id
|
||||||
override fun hashCode() = id.hashCode()
|
override fun hashCode() = id.hashCode()
|
||||||
}
|
}
|
||||||
@ -468,6 +468,6 @@ class InMemoryMessagingNetwork(
|
|||||||
1,
|
1,
|
||||||
message.uniqueMessageId,
|
message.uniqueMessageId,
|
||||||
message.debugTimestamp,
|
message.debugTimestamp,
|
||||||
X509Utilities.getDevX509Name(sender.description))
|
sender.description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
|||||||
import net.corda.testing.MOCK_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.nio.file.FileSystem
|
import java.nio.file.FileSystem
|
||||||
@ -287,9 +288,9 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
|
|
||||||
val config = TestNodeConfiguration(
|
val config = TestNodeConfiguration(
|
||||||
baseDirectory = path,
|
baseDirectory = path,
|
||||||
myLegalName = legalName ?: "Mock Company $id",
|
myLegalName = X500Name(legalName ?: "CN=Mock Company $id,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"),
|
||||||
networkMapService = null,
|
networkMapService = null,
|
||||||
dataSourceProperties = makeTestDataSourceProperties("node_${id}_net_$networkId"))
|
dataSourceProperties = makeTestDataSourceProperties(X500Name("CN=node_${id}_net_$networkId,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")))
|
||||||
val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, overrideServices, entropyRoot)
|
val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, overrideServices, entropyRoot)
|
||||||
if (start) {
|
if (start) {
|
||||||
node.setup().start()
|
node.setup().start()
|
||||||
|
@ -176,7 +176,7 @@ class MockStorageService(override val attachments: AttachmentStorage = MockAttac
|
|||||||
*
|
*
|
||||||
* @param nodeName Reflects the "instance" of the in-memory database. Defaults to a random string.
|
* @param nodeName Reflects the "instance" of the in-memory database. Defaults to a random string.
|
||||||
*/
|
*/
|
||||||
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
fun makeTestDataSourceProperties(nodeName: X500Name = X509Utilities.getDevX509Name(SecureHash.randomSHA256().toString())): Properties {
|
||||||
val props = Properties()
|
val props = Properties()
|
||||||
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
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.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.testing.node
|
|||||||
import com.codahale.metrics.MetricRegistry
|
import com.codahale.metrics.MetricRegistry
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.testing.MOCK_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
@ -16,6 +17,7 @@ import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
|||||||
import net.corda.node.utilities.configureDatabase
|
import net.corda.node.utilities.configureDatabase
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import net.corda.testing.freeLocalHostAndPort
|
import net.corda.testing.freeLocalHostAndPort
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
@ -32,7 +34,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL
|
|||||||
val userService = RPCUserServiceImpl(config.rpcUsers)
|
val userService = RPCUserServiceImpl(config.rpcUsers)
|
||||||
val monitoringService = MonitoringService(MetricRegistry())
|
val monitoringService = MonitoringService(MetricRegistry())
|
||||||
val identity: KeyPair = generateKeyPair()
|
val identity: KeyPair = generateKeyPair()
|
||||||
val executor = ServiceAffinityExecutor(config.myLegalName, 1)
|
val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1)
|
||||||
val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService)
|
val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService)
|
||||||
val networkMapRegistrationFuture: SettableFuture<Unit> = SettableFuture.create<Unit>()
|
val networkMapRegistrationFuture: SettableFuture<Unit> = SettableFuture.create<Unit>()
|
||||||
val net = database.transaction {
|
val net = database.transaction {
|
||||||
@ -54,7 +56,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL
|
|||||||
override val protocolVersion = 0
|
override val protocolVersion = 0
|
||||||
},
|
},
|
||||||
userService)
|
userService)
|
||||||
thread(name = config.myLegalName) {
|
thread(name = config.myLegalName.commonName) {
|
||||||
net.run()
|
net.run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package net.corda.demobench.model
|
|||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
@ -23,10 +25,9 @@ class InstallFactory : Controller() {
|
|||||||
|
|
||||||
val nodeConfig = NodeConfig(
|
val nodeConfig = NodeConfig(
|
||||||
tempDir,
|
tempDir,
|
||||||
config.getString("myLegalName"),
|
X500Name(config.getString("myLegalName")),
|
||||||
p2pPort,
|
p2pPort,
|
||||||
rpcPort,
|
rpcPort,
|
||||||
config.getString("nearestCity"),
|
|
||||||
webPort,
|
webPort,
|
||||||
h2Port,
|
h2Port,
|
||||||
extraServices,
|
extraServices,
|
||||||
@ -35,7 +36,7 @@ class InstallFactory : Controller() {
|
|||||||
|
|
||||||
if (config.hasPath("networkMapService")) {
|
if (config.hasPath("networkMapService")) {
|
||||||
val nmap = config.getConfig("networkMapService")
|
val nmap = config.getConfig("networkMapService")
|
||||||
nodeConfig.networkMap = NetworkMapConfig(nmap.getString("legalName"), nmap.parsePort("address"))
|
nodeConfig.networkMap = NetworkMapConfig(X500Name(nmap.getString("legalName")), nmap.parsePort("address"))
|
||||||
} else {
|
} else {
|
||||||
log.info("Node '${nodeConfig.legalName}' is the network map")
|
log.info("Node '${nodeConfig.legalName}' is the network map")
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package net.corda.demobench.model
|
package net.corda.demobench.model
|
||||||
|
|
||||||
open class NetworkMapConfig(val legalName: String, val p2pPort: Int) {
|
import net.corda.core.crypto.commonName
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
|
||||||
val key: String = legalName.toKey()
|
open class NetworkMapConfig(val legalName: X500Name, val p2pPort: Int) {
|
||||||
|
|
||||||
|
val key: String = legalName.commonName.toKey()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package net.corda.demobench.model
|
|||||||
|
|
||||||
import com.typesafe.config.*
|
import com.typesafe.config.*
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -9,10 +11,9 @@ import java.nio.file.StandardCopyOption
|
|||||||
|
|
||||||
class NodeConfig(
|
class NodeConfig(
|
||||||
baseDir: Path,
|
baseDir: Path,
|
||||||
legalName: String,
|
legalName: X500Name,
|
||||||
p2pPort: Int,
|
p2pPort: Int,
|
||||||
val rpcPort: Int,
|
val rpcPort: Int,
|
||||||
val nearestCity: String,
|
|
||||||
val webPort: Int,
|
val webPort: Int,
|
||||||
val h2Port: Int,
|
val h2Port: Int,
|
||||||
val extraServices: List<String>,
|
val extraServices: List<String>,
|
||||||
@ -25,6 +26,7 @@ class NodeConfig(
|
|||||||
val defaultUser = user("guest")
|
val defaultUser = user("guest")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val nearestCity: String? = legalName.getRDNs(BCStyle.L).singleOrNull()?.typesAndValues?.singleOrNull()?.value?.toString()
|
||||||
val nodeDir: Path = baseDir.resolve(key)
|
val nodeDir: Path = baseDir.resolve(key)
|
||||||
override val pluginDir: Path = nodeDir.resolve("plugins")
|
override val pluginDir: Path = nodeDir.resolve("plugins")
|
||||||
val explorerDir: Path = baseDir.resolve("$key-explorer")
|
val explorerDir: Path = baseDir.resolve("$key-explorer")
|
||||||
@ -42,14 +44,13 @@ class NodeConfig(
|
|||||||
* which is mutable.
|
* which is mutable.
|
||||||
*/
|
*/
|
||||||
fun toFileConfig(): Config = ConfigFactory.empty()
|
fun toFileConfig(): Config = ConfigFactory.empty()
|
||||||
.withValue("myLegalName", valueFor(legalName))
|
.withValue("myLegalName", valueFor(legalName.toString()))
|
||||||
.withValue("p2pAddress", addressValueFor(p2pPort))
|
.withValue("p2pAddress", addressValueFor(p2pPort))
|
||||||
.withValue("nearestCity", valueFor(nearestCity))
|
|
||||||
.withValue("extraAdvertisedServiceIds", valueFor(extraServices))
|
.withValue("extraAdvertisedServiceIds", valueFor(extraServices))
|
||||||
.withFallback(optional("networkMapService", networkMap, {
|
.withFallback(optional("networkMapService", networkMap, {
|
||||||
c, n ->
|
c, n ->
|
||||||
c.withValue("address", addressValueFor(n.p2pPort))
|
c.withValue("address", addressValueFor(n.p2pPort))
|
||||||
.withValue("legalName", valueFor(n.legalName))
|
.withValue("legalName", valueFor(n.legalName.toString()))
|
||||||
}))
|
}))
|
||||||
.withValue("webAddress", addressValueFor(webPort))
|
.withValue("webAddress", addressValueFor(webPort))
|
||||||
.withValue("rpcAddress", addressValueFor(rpcPort))
|
.withValue("rpcAddress", addressValueFor(rpcPort))
|
||||||
@ -60,7 +61,7 @@ class NodeConfig(
|
|||||||
fun toText(): String = toFileConfig().root().render(renderOptions)
|
fun toText(): String = toFileConfig().root().render(renderOptions)
|
||||||
|
|
||||||
fun moveTo(baseDir: Path) = NodeConfig(
|
fun moveTo(baseDir: Path) = NodeConfig(
|
||||||
baseDir, legalName, p2pPort, rpcPort, nearestCity, webPort, h2Port, extraServices, users, networkMap
|
baseDir, legalName, p2pPort, rpcPort, webPort, h2Port, extraServices, users, networkMap
|
||||||
)
|
)
|
||||||
|
|
||||||
fun install(plugins: Collection<Path>) {
|
fun install(plugins: Collection<Path>) {
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.demobench.model
|
|||||||
|
|
||||||
import net.corda.demobench.plugin.PluginController
|
import net.corda.demobench.plugin.PluginController
|
||||||
import net.corda.demobench.pty.R3Pty
|
import net.corda.demobench.pty.R3Pty
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
@ -51,10 +52,9 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
|
|||||||
fun validate(nodeData: NodeData): NodeConfig? {
|
fun validate(nodeData: NodeData): NodeConfig? {
|
||||||
val config = NodeConfig(
|
val config = NodeConfig(
|
||||||
baseDir,
|
baseDir,
|
||||||
nodeData.legalName.value.trim(),
|
X500Name(nodeData.legalName.value.trim()),
|
||||||
nodeData.p2pPort.value,
|
nodeData.p2pPort.value,
|
||||||
nodeData.rpcPort.value,
|
nodeData.rpcPort.value,
|
||||||
nodeData.nearestCity.value.description.trim(),
|
|
||||||
nodeData.webPort.value,
|
nodeData.webPort.value,
|
||||||
nodeData.h2Port.value,
|
nodeData.h2Port.value,
|
||||||
nodeData.extraServices.value
|
nodeData.extraServices.value
|
||||||
|
@ -4,14 +4,16 @@ import com.jediterm.terminal.ui.JediTermWidget
|
|||||||
import com.jediterm.terminal.ui.UIUtil
|
import com.jediterm.terminal.ui.UIUtil
|
||||||
import com.jediterm.terminal.ui.settings.SettingsProvider
|
import com.jediterm.terminal.ui.settings.SettingsProvider
|
||||||
import com.pty4j.PtyProcess
|
import com.pty4j.PtyProcess
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.awt.Dimension
|
import java.awt.Dimension
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.charset.StandardCharsets.UTF_8
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class R3Pty(val name: String, settings: SettingsProvider, dimension: Dimension, val onExit: (Int) -> Unit) : AutoCloseable {
|
class R3Pty(val name: X500Name, settings: SettingsProvider, dimension: Dimension, val onExit: (Int) -> Unit) : AutoCloseable {
|
||||||
private companion object {
|
private companion object {
|
||||||
val log = loggerFor<R3Pty>()
|
val log = loggerFor<R3Pty>()
|
||||||
}
|
}
|
||||||
@ -32,7 +34,7 @@ class R3Pty(val name: String, settings: SettingsProvider, dimension: Dimension,
|
|||||||
val process = PtyProcess.exec(command, environment, workingDir)
|
val process = PtyProcess.exec(command, environment, workingDir)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return PtyProcessTtyConnector(name, process, UTF_8)
|
return PtyProcessTtyConnector(name.commonName, process, UTF_8)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
process.destroyForcibly()
|
process.destroyForcibly()
|
||||||
process.waitFor(30, TimeUnit.SECONDS)
|
process.waitFor(30, TimeUnit.SECONDS)
|
||||||
|
@ -263,11 +263,11 @@ class NodeTabView : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun launchNode(config: NodeConfig) {
|
private fun launchNode(config: NodeConfig) {
|
||||||
val countryCode = CityDatabase.cityMap[config.nearestCity]?.countryCode
|
val countryCode = CityDatabase.cityMap[config.nearestCity ?: "Nowhere"]?.countryCode
|
||||||
if (countryCode != null) {
|
if (countryCode != null) {
|
||||||
nodeTab.graphic = ImageView(flags.get()[countryCode]).apply { fitWidth = 24.0; isPreserveRatio = true }
|
nodeTab.graphic = ImageView(flags.get()[countryCode]).apply { fitWidth = 24.0; isPreserveRatio = true }
|
||||||
}
|
}
|
||||||
nodeTab.text = config.legalName
|
nodeTab.text = config.legalName.toString()
|
||||||
nodeTerminalView.open(config) { exitCode ->
|
nodeTerminalView.open(config) { exitCode ->
|
||||||
Platform.runLater {
|
Platform.runLater {
|
||||||
if (exitCode == 0)
|
if (exitCode == 0)
|
||||||
|
@ -64,7 +64,7 @@ class NodeTerminalView : Fragment() {
|
|||||||
private lateinit var swingTerminal: SwingNode
|
private lateinit var swingTerminal: SwingNode
|
||||||
|
|
||||||
fun open(config: NodeConfig, onExit: (Int) -> Unit) {
|
fun open(config: NodeConfig, onExit: (Int) -> Unit) {
|
||||||
nodeName.text = config.legalName
|
nodeName.text = config.legalName.toString()
|
||||||
|
|
||||||
swingTerminal = SwingNode()
|
swingTerminal = SwingNode()
|
||||||
swingTerminal.setOnMouseClicked {
|
swingTerminal.setOnMouseClicked {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.demobench.model
|
package net.corda.demobench.model
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -7,7 +8,7 @@ class NetworkMapConfigTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun keyValue() {
|
fun keyValue() {
|
||||||
val config = NetworkMapConfig("My\tNasty Little\rLabel\n", 10000)
|
val config = NetworkMapConfig(X500Name("CN=My\tNasty Little\rLabel\n"), 10000)
|
||||||
assertEquals("mynastylittlelabel", config.key)
|
assertEquals("mynastylittlelabel", config.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.node.services.config.FullNodeConfiguration
|
|||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
import net.corda.nodeapi.config.parseAs
|
import net.corda.nodeapi.config.parseAs
|
||||||
import net.corda.webserver.WebServerConfig
|
import net.corda.webserver.WebServerConfig
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -22,41 +23,39 @@ import kotlin.test.assertFalse
|
|||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
|
||||||
class NodeConfigTest {
|
class NodeConfigTest {
|
||||||
|
|
||||||
private val baseDir: Path = Paths.get(".").toAbsolutePath()
|
companion object {
|
||||||
|
private val baseDir: Path = Paths.get(".").toAbsolutePath()
|
||||||
|
private val myLegalName = X500Name("CN=My Name,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test name`() {
|
fun `test name`() {
|
||||||
val config = createConfig(legalName = "My Name")
|
val config = createConfig(legalName = myLegalName)
|
||||||
assertEquals("My Name", config.legalName)
|
assertEquals(myLegalName, config.legalName)
|
||||||
assertEquals("myname", config.key)
|
assertEquals("myname", config.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test node directory`() {
|
fun `test node directory`() {
|
||||||
val config = createConfig(legalName = "My Name")
|
val config = createConfig(legalName = myLegalName)
|
||||||
assertEquals(baseDir / "myname", config.nodeDir)
|
assertEquals(baseDir / "myname", config.nodeDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test explorer directory`() {
|
fun `test explorer directory`() {
|
||||||
val config = createConfig(legalName = "My Name")
|
val config = createConfig(legalName = myLegalName)
|
||||||
assertEquals(baseDir / "myname-explorer", config.explorerDir)
|
assertEquals(baseDir / "myname-explorer", config.explorerDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test plugin directory`() {
|
fun `test plugin directory`() {
|
||||||
val config = createConfig(legalName = "My Name")
|
val config = createConfig(legalName = myLegalName)
|
||||||
assertEquals(baseDir / "myname" / "plugins", config.pluginDir)
|
assertEquals(baseDir / "myname" / "plugins", config.pluginDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `test nearest city`() {
|
|
||||||
val config = createConfig(nearestCity = "Leicester")
|
|
||||||
assertEquals("Leicester", config.nearestCity)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test P2P port`() {
|
fun `test P2P port`() {
|
||||||
val config = createConfig(p2pPort = 10001)
|
val config = createConfig(p2pPort = 10001)
|
||||||
@ -134,8 +133,7 @@ class NodeConfigTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test config text`() {
|
fun `test config text`() {
|
||||||
val config = createConfig(
|
val config = createConfig(
|
||||||
legalName = "My Name",
|
legalName = myLegalName,
|
||||||
nearestCity = "Stockholm",
|
|
||||||
p2pPort = 10001,
|
p2pPort = 10001,
|
||||||
rpcPort = 40002,
|
rpcPort = 40002,
|
||||||
webPort = 20001,
|
webPort = 20001,
|
||||||
@ -147,7 +145,6 @@ class NodeConfigTest {
|
|||||||
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
||||||
+ "\"h2port\":30001,"
|
+ "\"h2port\":30001,"
|
||||||
+ "\"myLegalName\":\"My Name\","
|
+ "\"myLegalName\":\"My Name\","
|
||||||
+ "\"nearestCity\":\"Stockholm\","
|
|
||||||
+ "\"p2pAddress\":\"localhost:10001\","
|
+ "\"p2pAddress\":\"localhost:10001\","
|
||||||
+ "\"rpcAddress\":\"localhost:40002\","
|
+ "\"rpcAddress\":\"localhost:40002\","
|
||||||
+ "\"rpcUsers\":["
|
+ "\"rpcUsers\":["
|
||||||
@ -161,8 +158,7 @@ class NodeConfigTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test config text with network map`() {
|
fun `test config text with network map`() {
|
||||||
val config = createConfig(
|
val config = createConfig(
|
||||||
legalName = "My Name",
|
legalName = myLegalName,
|
||||||
nearestCity = "Stockholm",
|
|
||||||
p2pPort = 10001,
|
p2pPort = 10001,
|
||||||
rpcPort = 40002,
|
rpcPort = 40002,
|
||||||
webPort = 20001,
|
webPort = 20001,
|
||||||
@ -170,13 +166,12 @@ class NodeConfigTest {
|
|||||||
services = listOf("my.service"),
|
services = listOf("my.service"),
|
||||||
users = listOf(user("jenny"))
|
users = listOf(user("jenny"))
|
||||||
)
|
)
|
||||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
||||||
|
|
||||||
assertEquals(prettyPrint("{"
|
assertEquals(prettyPrint("{"
|
||||||
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
||||||
+ "\"h2port\":30001,"
|
+ "\"h2port\":30001,"
|
||||||
+ "\"myLegalName\":\"My Name\","
|
+ "\"myLegalName\":\"My Name\","
|
||||||
+ "\"nearestCity\":\"Stockholm\","
|
|
||||||
+ "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH\"},"
|
+ "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH\"},"
|
||||||
+ "\"p2pAddress\":\"localhost:10001\","
|
+ "\"p2pAddress\":\"localhost:10001\","
|
||||||
+ "\"rpcAddress\":\"localhost:40002\","
|
+ "\"rpcAddress\":\"localhost:40002\","
|
||||||
@ -191,8 +186,7 @@ class NodeConfigTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `reading node configuration`() {
|
fun `reading node configuration`() {
|
||||||
val config = createConfig(
|
val config = createConfig(
|
||||||
legalName = "My Name",
|
legalName = myLegalName,
|
||||||
nearestCity = "Stockholm",
|
|
||||||
p2pPort = 10001,
|
p2pPort = 10001,
|
||||||
rpcPort = 40002,
|
rpcPort = 40002,
|
||||||
webPort = 20001,
|
webPort = 20001,
|
||||||
@ -200,7 +194,7 @@ class NodeConfigTest {
|
|||||||
services = listOf("my.service"),
|
services = listOf("my.service"),
|
||||||
users = listOf(user("jenny"))
|
users = listOf(user("jenny"))
|
||||||
)
|
)
|
||||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
||||||
|
|
||||||
val nodeConfig = config.toFileConfig()
|
val nodeConfig = config.toFileConfig()
|
||||||
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
||||||
@ -208,8 +202,8 @@ class NodeConfigTest {
|
|||||||
.resolve()
|
.resolve()
|
||||||
val fullConfig = nodeConfig.parseAs<FullNodeConfiguration>()
|
val fullConfig = nodeConfig.parseAs<FullNodeConfiguration>()
|
||||||
|
|
||||||
assertEquals("My Name", fullConfig.myLegalName)
|
assertEquals(myLegalName, fullConfig.myLegalName)
|
||||||
assertEquals("Stockholm", fullConfig.nearestCity)
|
assertEquals("London", fullConfig.nearestCity)
|
||||||
assertEquals(localPort(40002), fullConfig.rpcAddress)
|
assertEquals(localPort(40002), fullConfig.rpcAddress)
|
||||||
assertEquals(localPort(10001), fullConfig.p2pAddress)
|
assertEquals(localPort(10001), fullConfig.p2pAddress)
|
||||||
assertEquals(listOf("my.service"), fullConfig.extraAdvertisedServiceIds)
|
assertEquals(listOf("my.service"), fullConfig.extraAdvertisedServiceIds)
|
||||||
@ -222,8 +216,7 @@ class NodeConfigTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `reading webserver configuration`() {
|
fun `reading webserver configuration`() {
|
||||||
val config = createConfig(
|
val config = createConfig(
|
||||||
legalName = "My Name",
|
legalName = myLegalName,
|
||||||
nearestCity = "Stockholm",
|
|
||||||
p2pPort = 10001,
|
p2pPort = 10001,
|
||||||
rpcPort = 40002,
|
rpcPort = 40002,
|
||||||
webPort = 20001,
|
webPort = 20001,
|
||||||
@ -231,7 +224,7 @@ class NodeConfigTest {
|
|||||||
services = listOf("my.service"),
|
services = listOf("my.service"),
|
||||||
users = listOf(user("jenny"))
|
users = listOf(user("jenny"))
|
||||||
)
|
)
|
||||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
||||||
|
|
||||||
val nodeConfig = config.toFileConfig()
|
val nodeConfig = config.toFileConfig()
|
||||||
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
||||||
@ -247,7 +240,7 @@ class NodeConfigTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test moving`() {
|
fun `test moving`() {
|
||||||
val config = createConfig(legalName = "My Name")
|
val config = createConfig(legalName = myLegalName)
|
||||||
|
|
||||||
val elsewhere = baseDir / "elsewhere"
|
val elsewhere = baseDir / "elsewhere"
|
||||||
val moved = config.moveTo(elsewhere)
|
val moved = config.moveTo(elsewhere)
|
||||||
@ -257,8 +250,7 @@ class NodeConfigTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createConfig(
|
private fun createConfig(
|
||||||
legalName: String = "Unknown",
|
legalName: X500Name = X500Name("CN=Unknown,O=R3,OU=corda,L=Nowhere,C=UK"),
|
||||||
nearestCity: String = "Nowhere",
|
|
||||||
p2pPort: Int = -1,
|
p2pPort: Int = -1,
|
||||||
rpcPort: Int = -1,
|
rpcPort: Int = -1,
|
||||||
webPort: Int = -1,
|
webPort: Int = -1,
|
||||||
@ -268,7 +260,6 @@ class NodeConfigTest {
|
|||||||
) = NodeConfig(
|
) = NodeConfig(
|
||||||
baseDir,
|
baseDir,
|
||||||
legalName = legalName,
|
legalName = legalName,
|
||||||
nearestCity = nearestCity,
|
|
||||||
p2pPort = p2pPort,
|
p2pPort = p2pPort,
|
||||||
rpcPort = rpcPort,
|
rpcPort = rpcPort,
|
||||||
webPort = webPort,
|
webPort = webPort,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package net.corda.demobench.model
|
package net.corda.demobench.model
|
||||||
|
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY
|
import net.corda.core.utilities.DUMMY_NOTARY
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -11,11 +13,13 @@ class NodeControllerTest {
|
|||||||
|
|
||||||
private val baseDir: Path = Paths.get(".").toAbsolutePath()
|
private val baseDir: Path = Paths.get(".").toAbsolutePath()
|
||||||
private val controller = NodeController({ _, _ -> })
|
private val controller = NodeController({ _, _ -> })
|
||||||
|
private val node1Name = X500Name("CN=Node 1,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")
|
||||||
|
private val node2Name = X500Name("CN=Node 2,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test unique nodes after validate`() {
|
fun `test unique nodes after validate`() {
|
||||||
val data = NodeData()
|
val data = NodeData()
|
||||||
data.legalName.value = "Node 1"
|
data.legalName.value = node1Name.toString()
|
||||||
assertNotNull(controller.validate(data))
|
assertNotNull(controller.validate(data))
|
||||||
assertNull(controller.validate(data))
|
assertNull(controller.validate(data))
|
||||||
}
|
}
|
||||||
@ -23,7 +27,7 @@ class NodeControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test unique key after validate`() {
|
fun `test unique key after validate`() {
|
||||||
val data = NodeData()
|
val data = NodeData()
|
||||||
data.legalName.value = "Node 1"
|
data.legalName.value = node1Name.toString()
|
||||||
|
|
||||||
assertFalse(controller.keyExists("node1"))
|
assertFalse(controller.keyExists("node1"))
|
||||||
controller.validate(data)
|
controller.validate(data)
|
||||||
@ -33,7 +37,7 @@ class NodeControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test matching name after validate`() {
|
fun `test matching name after validate`() {
|
||||||
val data = NodeData()
|
val data = NodeData()
|
||||||
data.legalName.value = "Node 1"
|
data.legalName.value = node1Name.toString()
|
||||||
|
|
||||||
assertFalse(controller.nameExists("Node 1"))
|
assertFalse(controller.nameExists("Node 1"))
|
||||||
assertFalse(controller.nameExists("Node1"))
|
assertFalse(controller.nameExists("Node1"))
|
||||||
@ -47,7 +51,7 @@ class NodeControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test first validated node becomes network map`() {
|
fun `test first validated node becomes network map`() {
|
||||||
val data = NodeData()
|
val data = NodeData()
|
||||||
data.legalName.value = "Node 1"
|
data.legalName.value = node1Name.toString()
|
||||||
data.p2pPort.value = 100000
|
data.p2pPort.value = 100000
|
||||||
|
|
||||||
assertFalse(controller.hasNetworkMap())
|
assertFalse(controller.hasNetworkMap())
|
||||||
@ -57,14 +61,14 @@ class NodeControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test register unique nodes`() {
|
fun `test register unique nodes`() {
|
||||||
val config = createConfig(legalName = "Node 2")
|
val config = createConfig(legalName = node2Name)
|
||||||
assertTrue(controller.register(config))
|
assertTrue(controller.register(config))
|
||||||
assertFalse(controller.register(config))
|
assertFalse(controller.register(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test unique key after register`() {
|
fun `test unique key after register`() {
|
||||||
val config = createConfig(legalName = "Node 2")
|
val config = createConfig(legalName = node2Name)
|
||||||
|
|
||||||
assertFalse(controller.keyExists("node2"))
|
assertFalse(controller.keyExists("node2"))
|
||||||
controller.register(config)
|
controller.register(config)
|
||||||
@ -73,7 +77,7 @@ class NodeControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test matching name after register`() {
|
fun `test matching name after register`() {
|
||||||
val config = createConfig(legalName = "Node 2")
|
val config = createConfig(legalName = node2Name)
|
||||||
|
|
||||||
assertFalse(controller.nameExists("Node 2"))
|
assertFalse(controller.nameExists("Node 2"))
|
||||||
assertFalse(controller.nameExists("Node2"))
|
assertFalse(controller.nameExists("Node2"))
|
||||||
@ -86,7 +90,7 @@ class NodeControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test register network map node`() {
|
fun `test register network map node`() {
|
||||||
val config = createConfig(legalName = "Node is Network Map")
|
val config = createConfig(legalName = X500Name("CN=Node is Network Map,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
||||||
assertTrue(config.isNetworkMap())
|
assertTrue(config.isNetworkMap())
|
||||||
|
|
||||||
assertFalse(controller.hasNetworkMap())
|
assertFalse(controller.hasNetworkMap())
|
||||||
@ -96,8 +100,8 @@ class NodeControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test register non-network-map node`() {
|
fun `test register non-network-map node`() {
|
||||||
val config = createConfig(legalName = "Node is not Network Map")
|
val config = createConfig(legalName = X500Name("CN=Node is not Network Map,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
||||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 10000)
|
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 10000)
|
||||||
assertFalse(config.isNetworkMap())
|
assertFalse(config.isNetworkMap())
|
||||||
|
|
||||||
assertFalse(controller.hasNetworkMap())
|
assertFalse(controller.hasNetworkMap())
|
||||||
@ -151,7 +155,7 @@ class NodeControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `dispose node`() {
|
fun `dispose node`() {
|
||||||
val config = createConfig(legalName = "MyName")
|
val config = createConfig(legalName = X500Name("CN=MyName,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
||||||
controller.register(config)
|
controller.register(config)
|
||||||
|
|
||||||
assertEquals(NodeState.STARTING, config.state)
|
assertEquals(NodeState.STARTING, config.state)
|
||||||
@ -162,8 +166,7 @@ class NodeControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createConfig(
|
private fun createConfig(
|
||||||
legalName: String = "Unknown",
|
legalName: X500Name = X509Utilities.getDevX509Name("Unknown"),
|
||||||
nearestCity: String = "Nowhere",
|
|
||||||
p2pPort: Int = -1,
|
p2pPort: Int = -1,
|
||||||
rpcPort: Int = -1,
|
rpcPort: Int = -1,
|
||||||
webPort: Int = -1,
|
webPort: Int = -1,
|
||||||
@ -173,7 +176,6 @@ class NodeControllerTest {
|
|||||||
) = NodeConfig(
|
) = NodeConfig(
|
||||||
baseDir,
|
baseDir,
|
||||||
legalName = legalName,
|
legalName = legalName,
|
||||||
nearestCity = nearestCity,
|
|
||||||
p2pPort = p2pPort,
|
p2pPort = p2pPort,
|
||||||
rpcPort = rpcPort,
|
rpcPort = rpcPort,
|
||||||
webPort = webPort,
|
webPort = webPort,
|
||||||
|
Loading…
Reference in New Issue
Block a user