mirror of
https://github.com/corda/corda.git
synced 2024-12-24 07:06:44 +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.InVMConnectorFactory
|
||||
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import java.util.*
|
||||
@ -74,7 +75,7 @@ abstract class AbstractClientRPCTest {
|
||||
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) {
|
||||
val msg = serverSession.createMessage(false).apply {
|
||||
writeBodyBufferBytes(data.bytes)
|
||||
|
@ -110,6 +110,8 @@ object X509Utilities {
|
||||
* Return a bogus X509 for dev purposes. Use [getX509Name] for something more real.
|
||||
*/
|
||||
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)
|
||||
nameBuilder.addRDN(BCStyle.CN, commonName)
|
||||
nameBuilder.addRDN(BCStyle.O, "R3")
|
||||
|
@ -4,6 +4,7 @@ import com.google.common.net.HostAndPort
|
||||
import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigUtil
|
||||
import net.corda.core.noneOrSingle
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.net.Proxy
|
||||
import java.net.URL
|
||||
@ -70,6 +71,7 @@ private fun Config.getSingleValue(path: String, type: KType): Any? {
|
||||
Path::class -> Paths.get(getString(path))
|
||||
URL::class -> URL(getString(path))
|
||||
Properties::class -> getConfig(path).toProperties()
|
||||
X500Name::class -> X500Name(getString(path))
|
||||
else -> if (typeClass.java.isEnum) {
|
||||
parseEnum(typeClass.java, getString(path))
|
||||
} else {
|
||||
|
@ -8,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.readLines
|
||||
import net.corda.core.utilities.DUMMY_BANK_A
|
||||
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.services.api.RegulatorService
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
@ -42,7 +43,7 @@ class DriverTests {
|
||||
fun `simple node startup and shutdown`() {
|
||||
val handles = driver {
|
||||
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))
|
||||
}
|
||||
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.ListenableFuture
|
||||
import net.corda.core.*
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.messaging.MessageRecipients
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
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.node.NodeBasedTest
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
import java.util.concurrent.CountDownLatch
|
||||
@ -27,6 +29,11 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class P2PMessagingTest : NodeBasedTest() {
|
||||
private companion object {
|
||||
val DISTRIBUTED_SERVICE_NAME = X509Utilities.getDevX509Name("DistributedService")
|
||||
val SERVICE_2_NAME = X509Utilities.getDevX509Name("Service Node 2")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `network map will work after restart`() {
|
||||
val identities = listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
|
||||
@ -55,15 +62,14 @@ class P2PMessagingTest : NodeBasedTest() {
|
||||
// TODO Use a dummy distributed service
|
||||
@Test
|
||||
fun `communicating with a distributed service which the network map node is part of`() {
|
||||
val serviceName = "DistributedService"
|
||||
|
||||
val root = tempFolder.root.toPath()
|
||||
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,
|
||||
serviceName)
|
||||
DISTRIBUTED_SERVICE_NAME)
|
||||
|
||||
val distributedService = ServiceInfo(RaftValidatingNotaryService.type, serviceName)
|
||||
val distributedService = ServiceInfo(RaftValidatingNotaryService.type, DISTRIBUTED_SERVICE_NAME)
|
||||
val notaryClusterAddress = freeLocalHostAndPort()
|
||||
startNetworkMapNode(
|
||||
DUMMY_MAP.name,
|
||||
@ -71,7 +77,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
||||
configOverrides = mapOf("notaryNodeAddress" to notaryClusterAddress.toString()))
|
||||
val (serviceNode2, alice) = Futures.allAsList(
|
||||
startNode(
|
||||
"Service Node 2",
|
||||
SERVICE_2_NAME,
|
||||
advertisedServices = setOf(distributedService),
|
||||
configOverrides = mapOf(
|
||||
"notaryNodeAddress" to freeLocalHostAndPort().toString(),
|
||||
@ -79,14 +85,13 @@ class P2PMessagingTest : NodeBasedTest() {
|
||||
startNode(ALICE.name)
|
||||
).getOrThrow()
|
||||
|
||||
assertAllNodesAreUsed(listOf(networkMapNode, serviceNode2), serviceName, alice)
|
||||
assertAllNodesAreUsed(listOf(networkMapNode, serviceNode2), DISTRIBUTED_SERVICE_NAME, alice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `communicating with a distributed service which we're part of`() {
|
||||
val serviceName = "Distributed Service"
|
||||
val distributedService = startNotaryCluster(serviceName, 2).getOrThrow()
|
||||
assertAllNodesAreUsed(distributedService, serviceName, distributedService[0])
|
||||
val distributedService = startNotaryCluster(DISTRIBUTED_SERVICE_NAME, 2).getOrThrow()
|
||||
assertAllNodesAreUsed(distributedService, DISTRIBUTED_SERVICE_NAME, distributedService[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -183,13 +188,13 @@ class P2PMessagingTest : NodeBasedTest() {
|
||||
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
|
||||
participatingServiceNodes.forEach { node ->
|
||||
node.respondWith(node.info)
|
||||
}
|
||||
val serviceAddress = originatingNode.services.networkMapCache.run {
|
||||
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName)!!)!!)
|
||||
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName.toString())!!)!!)
|
||||
}
|
||||
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
|
||||
|
@ -2,12 +2,15 @@ package net.corda.services.messaging
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.div
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.random63BitValue
|
||||
import net.corda.core.seconds
|
||||
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.services.config.configureWithDevSSLCertificate
|
||||
import net.corda.node.services.messaging.sendRequest
|
||||
@ -21,6 +24,7 @@ import net.corda.testing.node.NodeBasedTest
|
||||
import net.corda.testing.node.SimpleNode
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.TimeoutException
|
||||
@ -42,9 +46,9 @@ class P2PSecurityTest : NodeBasedTest() {
|
||||
|
||||
@Test
|
||||
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
|
||||
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
|
||||
// to the attacker as the TLS CN will not match the legal name it has just provided
|
||||
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(
|
||||
baseDirectory = tempFolder.root.toPath() / legalName,
|
||||
baseDirectory = tempFolder.root.toPath() / legalName.commonName,
|
||||
myLegalName = legalName,
|
||||
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
|
||||
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 registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
||||
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.
|
||||
val privKeyFile = dir / privateKeyFileName
|
||||
val pubIdentityFile = dir / publicKeyFileName
|
||||
val identityName = serviceName ?: configuration.myLegalName
|
||||
val identityName = serviceName ?: configuration.myLegalName.toString()
|
||||
|
||||
val identityAndKey = if (!privKeyFile.exists()) {
|
||||
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.utilities.loggerFor
|
||||
import net.corda.nodeapi.config.SSLConfiguration
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.nio.file.Path
|
||||
|
||||
object ConfigHelper {
|
||||
@ -45,7 +46,7 @@ object ConfigHelper {
|
||||
*/
|
||||
fun NodeConfiguration.configureWithDevSSLCertificate() = configureDevKeyAndTrustStores(myLegalName)
|
||||
|
||||
fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: String) {
|
||||
fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: X500Name) {
|
||||
certificatesDirectory.createDirectories()
|
||||
if (!trustStoreFile.exists()) {
|
||||
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.config.OldConfig
|
||||
import net.corda.nodeapi.config.SSLConfiguration
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.net.URL
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
@ -20,7 +21,7 @@ import java.util.*
|
||||
interface NodeConfiguration : SSLConfiguration {
|
||||
val baseDirectory: Path
|
||||
override val certificatesDirectory: Path get() = baseDirectory / "certificates"
|
||||
val myLegalName: String
|
||||
val myLegalName: X500Name
|
||||
val networkMapService: NetworkMapInfo?
|
||||
val minimumPlatformVersion: Int
|
||||
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",
|
||||
ReplaceWith("baseDirectory"))
|
||||
val basedir: Path,
|
||||
override val myLegalName: String,
|
||||
override val myLegalName: X500Name,
|
||||
override val nearestCity: String,
|
||||
override val emailAddress: String,
|
||||
override val keyStorePassword: String,
|
||||
|
@ -238,7 +238,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
.loadCertificateFromKeyStore(config.keyStoreFile, config.keyStorePassword, CORDA_CLIENT_CA)
|
||||
val ourSubjectDN = X500Name(ourCertificate.subjectDN.name)
|
||||
// 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"
|
||||
}
|
||||
val defaultCertPolicies = mapOf(
|
||||
@ -398,18 +398,18 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
private fun getBridgeName(queueName: String, hostAndPort: HostAndPort): String = "$queueName -> $hostAndPort"
|
||||
|
||||
// This is called on one of Artemis' background threads
|
||||
internal fun hostVerificationFail(peerLegalName: String, expectedCommonName: String) {
|
||||
log.error("Peer has wrong CN - expected $expectedCommonName but got $peerLegalName. This is either a fatal " +
|
||||
internal fun hostVerificationFail(peerLegalName: X500Name, expectedLegalName: X500Name) {
|
||||
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!")
|
||||
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!
|
||||
_networkMapConnectionFuture!!.setException(IOException("${config.networkMapService} failed host verification check"))
|
||||
}
|
||||
}
|
||||
|
||||
// This is called on one of Artemis' background threads
|
||||
internal fun onTcpConnection(peerLegalName: String) {
|
||||
if (peerLegalName == config.networkMapService?.legalName) {
|
||||
internal fun onTcpConnection(peerLegalName: X500Name) {
|
||||
if (peerLegalName.toString() == config.networkMapService?.legalName) {
|
||||
_networkMapConnectionFuture!!.set(Unit)
|
||||
}
|
||||
}
|
||||
@ -437,7 +437,9 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
||||
protocolManager: ClientProtocolManager?) :
|
||||
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
|
||||
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? {
|
||||
val connection = super.createConnection() as NettyConnection?
|
||||
@ -451,9 +453,8 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
||||
.peerPrincipal
|
||||
.name
|
||||
.let(::X500Name)
|
||||
.commonName
|
||||
// TODO Verify on the entire principle (subject)
|
||||
if (peerLegalName != expectedCommonName) {
|
||||
if (peerLegalName.commonName != expectedCommonName.commonName) {
|
||||
connection.close()
|
||||
server!!.hostVerificationFail(peerLegalName, expectedCommonName)
|
||||
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) {
|
||||
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
||||
messagingExecutor.fetchFrom {
|
||||
|
@ -37,7 +37,7 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||
* are handled, this is probably the wrong system.
|
||||
*/
|
||||
// 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
|
||||
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)
|
||||
if (rpcUser != null) {
|
||||
return rpcUser
|
||||
} else if (X500Name(validatedUser).commonName == nodeLegalName) {
|
||||
return nodeUser
|
||||
} 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")
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ class NetworkRegistrationHelper(val config: NodeConfiguration, val certService:
|
||||
private fun submitOrResumeCertificateSigningRequest(keyPair: KeyPair): String {
|
||||
// Retrieve request id from file if exists, else post a request to server.
|
||||
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()
|
||||
JcaPEMWriter(writer).use {
|
||||
it.writeObject(PemObject("CERTIFICATE REQUEST", request.encoded))
|
||||
|
@ -34,7 +34,7 @@ class InteractiveShellTest {
|
||||
}
|
||||
|
||||
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 fun check(input: String, expected: String) {
|
||||
|
@ -4,6 +4,7 @@ import net.corda.core.utilities.ALICE
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.testing.testConfiguration
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.nio.file.Paths
|
||||
|
||||
@ -11,7 +12,7 @@ class FullNodeConfigurationTest {
|
||||
@Test
|
||||
fun `Artemis special characters not permitted in RPC usernames`() {
|
||||
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())))
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import net.corda.testing.freeLocalHostAndPort
|
||||
import net.corda.testing.node.makeTestDataSourceProperties
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -71,7 +72,7 @@ class ArtemisMessagingTests {
|
||||
userService = RPCUserServiceImpl(emptyList())
|
||||
config = TestNodeConfiguration(
|
||||
baseDirectory = baseDirectory,
|
||||
myLegalName = ALICE.name,
|
||||
myLegalName = X500Name(ALICE.name),
|
||||
networkMapService = null)
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())
|
||||
|
@ -39,7 +39,7 @@ class NetworkRegistrationHelperTest {
|
||||
|
||||
val config = TestNodeConfiguration(
|
||||
baseDirectory = tempFolder.root.toPath(),
|
||||
myLegalName = ALICE.name,
|
||||
myLegalName = X500Name(ALICE.name),
|
||||
networkMapService = null)
|
||||
|
||||
assertFalse(config.keyStoreFile.exists())
|
||||
|
@ -72,8 +72,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
|
||||
val cfg = TestNodeConfiguration(
|
||||
baseDirectory = config.baseDirectory,
|
||||
myLegalName = "CN=Bank $letter,O=Bank $letter,L=$city,C=$country",
|
||||
nearestCity = city,
|
||||
myLegalName = X500Name("CN=Bank $letter,O=Bank $letter,L=$city,C=$country"),
|
||||
networkMapService = null)
|
||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||
}
|
||||
@ -95,8 +94,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
require(advertisedServices.containsType(NetworkMapService.type))
|
||||
val cfg = TestNodeConfiguration(
|
||||
baseDirectory = config.baseDirectory,
|
||||
myLegalName = DUMMY_MAP.name,
|
||||
nearestCity = X500Name(DUMMY_MAP.name).location,
|
||||
myLegalName = X500Name(DUMMY_MAP.name),
|
||||
networkMapService = null)
|
||||
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))
|
||||
val cfg = TestNodeConfiguration(
|
||||
baseDirectory = config.baseDirectory,
|
||||
myLegalName = DUMMY_NOTARY.name,
|
||||
nearestCity = X500Name(DUMMY_NOTARY.name).location,
|
||||
myLegalName = X500Name(DUMMY_NOTARY.name),
|
||||
networkMapService = null)
|
||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||
}
|
||||
@ -118,7 +115,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
|
||||
object RatesOracleFactory : MockNetwork.Factory {
|
||||
// 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?,
|
||||
advertisedServices: Set<ServiceInfo>, id: Int, overrideServices: Map<ServiceInfo, KeyPair>?,
|
||||
@ -127,7 +124,6 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
val cfg = TestNodeConfiguration(
|
||||
baseDirectory = config.baseDirectory,
|
||||
myLegalName = RATES_SERVICE_NAME,
|
||||
nearestCity = X500Name(RATES_SERVICE_NAME).location,
|
||||
networkMapService = null)
|
||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||
override fun start(): MockNetwork.MockNode {
|
||||
@ -149,8 +145,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||
val cfg = TestNodeConfiguration(
|
||||
baseDirectory = config.baseDirectory,
|
||||
myLegalName = DUMMY_REGULATOR.name,
|
||||
nearestCity = X500Name(DUMMY_REGULATOR.name).location,
|
||||
myLegalName = X500Name(DUMMY_REGULATOR.name),
|
||||
networkMapService = null)
|
||||
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.
|
||||
|
@ -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 {
|
||||
fun emitRadarPulse(initialRadius: Double, targetRadius: Double, duration: Double): Pair<Circle, Animation> {
|
||||
val pulse = Circle(initialRadius).apply {
|
||||
@ -157,7 +157,7 @@ class VisualiserViewModel {
|
||||
view.root.children += longPulseOuterDot
|
||||
view.root.children += innerDot
|
||||
|
||||
val nameLabel = Label(label)
|
||||
val nameLabel = Label(label.toString())
|
||||
val nameLabelRect = StackPane(nameLabel).apply {
|
||||
styleClass += "node-label"
|
||||
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.makeTestDataSourceProperties
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||
import java.net.ServerSocket
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
@ -156,23 +157,24 @@ inline fun <reified P : FlowLogic<*>> AbstractNode.initiateSingleShotFlow(
|
||||
// TODO Replace this with testConfiguration
|
||||
data class TestNodeConfiguration(
|
||||
override val baseDirectory: Path,
|
||||
override val myLegalName: String,
|
||||
override val myLegalName: X500Name,
|
||||
override val networkMapService: NetworkMapInfo?,
|
||||
override val minimumPlatformVersion: Int = 1,
|
||||
override val keyStorePassword: String = "cordacadevpass",
|
||||
override val trustStorePassword: String = "trustpass",
|
||||
override val rpcUsers: List<User> = emptyList(),
|
||||
override val dataSourceProperties: Properties = makeTestDataSourceProperties(myLegalName),
|
||||
override val nearestCity: String = "Null Island",
|
||||
override val emailAddress: String = "",
|
||||
override val exportJMXto: String = "",
|
||||
override val devMode: Boolean = true,
|
||||
override val certificateSigningService: URL = URL("http://localhost"),
|
||||
override val certificateChainCheckPolicies: List<CertChainPolicyConfig> = emptyList(),
|
||||
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(
|
||||
basedir = baseDirectory,
|
||||
myLegalName = legalName,
|
||||
@ -198,7 +200,7 @@ fun testConfiguration(baseDirectory: Path, legalName: String, basePort: Int): Fu
|
||||
}
|
||||
|
||||
@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 keyStorePassword: String get() = "cordacadevpass"
|
||||
override val trustStorePassword: String get() = "trustpass"
|
||||
|
@ -7,12 +7,16 @@ import net.corda.nodeapi.ConnectionDirection
|
||||
import net.corda.nodeapi.config.SSLConfiguration
|
||||
import net.corda.testing.configureTestSSL
|
||||
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.
|
||||
*/
|
||||
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 session: ClientSession
|
||||
lateinit var producer: ClientProducer
|
||||
|
@ -127,10 +127,10 @@ class InMemoryMessagingNetwork(
|
||||
id: Int,
|
||||
executor: AffinityExecutor,
|
||||
advertisedServices: List<ServiceEntry>,
|
||||
description: String? = null,
|
||||
description: X500Name? = null,
|
||||
database: Database)
|
||||
: 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 {
|
||||
@ -198,8 +198,8 @@ class InMemoryMessagingNetwork(
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class PeerHandle(val id: Int, val description: String) : SingleMessageRecipient {
|
||||
override fun toString() = description
|
||||
data class PeerHandle(val id: Int, val description: X500Name) : SingleMessageRecipient {
|
||||
override fun toString() = description.toString()
|
||||
override fun equals(other: Any?) = other is PeerHandle && other.id == id
|
||||
override fun hashCode() = id.hashCode()
|
||||
}
|
||||
@ -468,6 +468,6 @@ class InMemoryMessagingNetwork(
|
||||
1,
|
||||
message.uniqueMessageId,
|
||||
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.TestNodeConfiguration
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.slf4j.Logger
|
||||
import java.math.BigInteger
|
||||
import java.nio.file.FileSystem
|
||||
@ -287,9 +288,9 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
||||
|
||||
val config = TestNodeConfiguration(
|
||||
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,
|
||||
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)
|
||||
if (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.
|
||||
*/
|
||||
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
||||
fun makeTestDataSourceProperties(nodeName: X500Name = X509Utilities.getDevX509Name(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")
|
||||
|
@ -3,6 +3,7 @@ package net.corda.testing.node
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.messaging.RPCOps
|
||||
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.transaction
|
||||
import net.corda.testing.freeLocalHostAndPort
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import java.io.Closeable
|
||||
import java.security.KeyPair
|
||||
@ -32,7 +34,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL
|
||||
val userService = RPCUserServiceImpl(config.rpcUsers)
|
||||
val monitoringService = MonitoringService(MetricRegistry())
|
||||
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 networkMapRegistrationFuture: SettableFuture<Unit> = SettableFuture.create<Unit>()
|
||||
val net = database.transaction {
|
||||
@ -54,7 +56,7 @@ class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeL
|
||||
override val protocolVersion = 0
|
||||
},
|
||||
userService)
|
||||
thread(name = config.myLegalName) {
|
||||
thread(name = config.myLegalName.commonName) {
|
||||
net.run()
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package net.corda.demobench.model
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.typesafe.config.Config
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
|
||||
import tornadofx.*
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
@ -23,10 +25,9 @@ class InstallFactory : Controller() {
|
||||
|
||||
val nodeConfig = NodeConfig(
|
||||
tempDir,
|
||||
config.getString("myLegalName"),
|
||||
X500Name(config.getString("myLegalName")),
|
||||
p2pPort,
|
||||
rpcPort,
|
||||
config.getString("nearestCity"),
|
||||
webPort,
|
||||
h2Port,
|
||||
extraServices,
|
||||
@ -35,7 +36,7 @@ class InstallFactory : Controller() {
|
||||
|
||||
if (config.hasPath("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 {
|
||||
log.info("Node '${nodeConfig.legalName}' is the network map")
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
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 net.corda.nodeapi.User
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
@ -9,10 +11,9 @@ import java.nio.file.StandardCopyOption
|
||||
|
||||
class NodeConfig(
|
||||
baseDir: Path,
|
||||
legalName: String,
|
||||
legalName: X500Name,
|
||||
p2pPort: Int,
|
||||
val rpcPort: Int,
|
||||
val nearestCity: String,
|
||||
val webPort: Int,
|
||||
val h2Port: Int,
|
||||
val extraServices: List<String>,
|
||||
@ -25,6 +26,7 @@ class NodeConfig(
|
||||
val defaultUser = user("guest")
|
||||
}
|
||||
|
||||
val nearestCity: String? = legalName.getRDNs(BCStyle.L).singleOrNull()?.typesAndValues?.singleOrNull()?.value?.toString()
|
||||
val nodeDir: Path = baseDir.resolve(key)
|
||||
override val pluginDir: Path = nodeDir.resolve("plugins")
|
||||
val explorerDir: Path = baseDir.resolve("$key-explorer")
|
||||
@ -42,14 +44,13 @@ class NodeConfig(
|
||||
* which is mutable.
|
||||
*/
|
||||
fun toFileConfig(): Config = ConfigFactory.empty()
|
||||
.withValue("myLegalName", valueFor(legalName))
|
||||
.withValue("myLegalName", valueFor(legalName.toString()))
|
||||
.withValue("p2pAddress", addressValueFor(p2pPort))
|
||||
.withValue("nearestCity", valueFor(nearestCity))
|
||||
.withValue("extraAdvertisedServiceIds", valueFor(extraServices))
|
||||
.withFallback(optional("networkMapService", networkMap, {
|
||||
c, n ->
|
||||
c.withValue("address", addressValueFor(n.p2pPort))
|
||||
.withValue("legalName", valueFor(n.legalName))
|
||||
.withValue("legalName", valueFor(n.legalName.toString()))
|
||||
}))
|
||||
.withValue("webAddress", addressValueFor(webPort))
|
||||
.withValue("rpcAddress", addressValueFor(rpcPort))
|
||||
@ -60,7 +61,7 @@ class NodeConfig(
|
||||
fun toText(): String = toFileConfig().root().render(renderOptions)
|
||||
|
||||
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>) {
|
||||
|
@ -2,6 +2,7 @@ package net.corda.demobench.model
|
||||
|
||||
import net.corda.demobench.plugin.PluginController
|
||||
import net.corda.demobench.pty.R3Pty
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import tornadofx.*
|
||||
import java.io.IOException
|
||||
import java.lang.management.ManagementFactory
|
||||
@ -51,10 +52,9 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
|
||||
fun validate(nodeData: NodeData): NodeConfig? {
|
||||
val config = NodeConfig(
|
||||
baseDir,
|
||||
nodeData.legalName.value.trim(),
|
||||
X500Name(nodeData.legalName.value.trim()),
|
||||
nodeData.p2pPort.value,
|
||||
nodeData.rpcPort.value,
|
||||
nodeData.nearestCity.value.description.trim(),
|
||||
nodeData.webPort.value,
|
||||
nodeData.h2Port.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.settings.SettingsProvider
|
||||
import com.pty4j.PtyProcess
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.awt.Dimension
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets.UTF_8
|
||||
import java.util.concurrent.Executors
|
||||
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 {
|
||||
val log = loggerFor<R3Pty>()
|
||||
}
|
||||
@ -32,7 +34,7 @@ class R3Pty(val name: String, settings: SettingsProvider, dimension: Dimension,
|
||||
val process = PtyProcess.exec(command, environment, workingDir)
|
||||
|
||||
try {
|
||||
return PtyProcessTtyConnector(name, process, UTF_8)
|
||||
return PtyProcessTtyConnector(name.commonName, process, UTF_8)
|
||||
} catch (e: Exception) {
|
||||
process.destroyForcibly()
|
||||
process.waitFor(30, TimeUnit.SECONDS)
|
||||
|
@ -263,11 +263,11 @@ class NodeTabView : Fragment() {
|
||||
}
|
||||
|
||||
private fun launchNode(config: NodeConfig) {
|
||||
val countryCode = CityDatabase.cityMap[config.nearestCity]?.countryCode
|
||||
val countryCode = CityDatabase.cityMap[config.nearestCity ?: "Nowhere"]?.countryCode
|
||||
if (countryCode != null) {
|
||||
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 ->
|
||||
Platform.runLater {
|
||||
if (exitCode == 0)
|
||||
|
@ -64,7 +64,7 @@ class NodeTerminalView : Fragment() {
|
||||
private lateinit var swingTerminal: SwingNode
|
||||
|
||||
fun open(config: NodeConfig, onExit: (Int) -> Unit) {
|
||||
nodeName.text = config.legalName
|
||||
nodeName.text = config.legalName.toString()
|
||||
|
||||
swingTerminal = SwingNode()
|
||||
swingTerminal.setOnMouseClicked {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.demobench.model
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -7,7 +8,7 @@ class NetworkMapConfigTest {
|
||||
|
||||
@Test
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.nodeapi.config.parseAs
|
||||
import net.corda.webserver.WebServerConfig
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.io.StringWriter
|
||||
import java.nio.file.Path
|
||||
@ -22,41 +23,39 @@ import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
|
||||
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
|
||||
fun `test name`() {
|
||||
val config = createConfig(legalName = "My Name")
|
||||
assertEquals("My Name", config.legalName)
|
||||
val config = createConfig(legalName = myLegalName)
|
||||
assertEquals(myLegalName, config.legalName)
|
||||
assertEquals("myname", config.key)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test node directory`() {
|
||||
val config = createConfig(legalName = "My Name")
|
||||
val config = createConfig(legalName = myLegalName)
|
||||
assertEquals(baseDir / "myname", config.nodeDir)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test explorer directory`() {
|
||||
val config = createConfig(legalName = "My Name")
|
||||
val config = createConfig(legalName = myLegalName)
|
||||
assertEquals(baseDir / "myname-explorer", config.explorerDir)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test plugin directory`() {
|
||||
val config = createConfig(legalName = "My Name")
|
||||
val config = createConfig(legalName = myLegalName)
|
||||
assertEquals(baseDir / "myname" / "plugins", config.pluginDir)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test nearest city`() {
|
||||
val config = createConfig(nearestCity = "Leicester")
|
||||
assertEquals("Leicester", config.nearestCity)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test P2P port`() {
|
||||
val config = createConfig(p2pPort = 10001)
|
||||
@ -134,8 +133,7 @@ class NodeConfigTest {
|
||||
@Test
|
||||
fun `test config text`() {
|
||||
val config = createConfig(
|
||||
legalName = "My Name",
|
||||
nearestCity = "Stockholm",
|
||||
legalName = myLegalName,
|
||||
p2pPort = 10001,
|
||||
rpcPort = 40002,
|
||||
webPort = 20001,
|
||||
@ -147,7 +145,6 @@ class NodeConfigTest {
|
||||
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
||||
+ "\"h2port\":30001,"
|
||||
+ "\"myLegalName\":\"My Name\","
|
||||
+ "\"nearestCity\":\"Stockholm\","
|
||||
+ "\"p2pAddress\":\"localhost:10001\","
|
||||
+ "\"rpcAddress\":\"localhost:40002\","
|
||||
+ "\"rpcUsers\":["
|
||||
@ -161,8 +158,7 @@ class NodeConfigTest {
|
||||
@Test
|
||||
fun `test config text with network map`() {
|
||||
val config = createConfig(
|
||||
legalName = "My Name",
|
||||
nearestCity = "Stockholm",
|
||||
legalName = myLegalName,
|
||||
p2pPort = 10001,
|
||||
rpcPort = 40002,
|
||||
webPort = 20001,
|
||||
@ -170,13 +166,12 @@ class NodeConfigTest {
|
||||
services = listOf("my.service"),
|
||||
users = listOf(user("jenny"))
|
||||
)
|
||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
||||
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
||||
|
||||
assertEquals(prettyPrint("{"
|
||||
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
||||
+ "\"h2port\":30001,"
|
||||
+ "\"myLegalName\":\"My Name\","
|
||||
+ "\"nearestCity\":\"Stockholm\","
|
||||
+ "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH\"},"
|
||||
+ "\"p2pAddress\":\"localhost:10001\","
|
||||
+ "\"rpcAddress\":\"localhost:40002\","
|
||||
@ -191,8 +186,7 @@ class NodeConfigTest {
|
||||
@Test
|
||||
fun `reading node configuration`() {
|
||||
val config = createConfig(
|
||||
legalName = "My Name",
|
||||
nearestCity = "Stockholm",
|
||||
legalName = myLegalName,
|
||||
p2pPort = 10001,
|
||||
rpcPort = 40002,
|
||||
webPort = 20001,
|
||||
@ -200,7 +194,7 @@ class NodeConfigTest {
|
||||
services = listOf("my.service"),
|
||||
users = listOf(user("jenny"))
|
||||
)
|
||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
||||
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
||||
|
||||
val nodeConfig = config.toFileConfig()
|
||||
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
||||
@ -208,8 +202,8 @@ class NodeConfigTest {
|
||||
.resolve()
|
||||
val fullConfig = nodeConfig.parseAs<FullNodeConfiguration>()
|
||||
|
||||
assertEquals("My Name", fullConfig.myLegalName)
|
||||
assertEquals("Stockholm", fullConfig.nearestCity)
|
||||
assertEquals(myLegalName, fullConfig.myLegalName)
|
||||
assertEquals("London", fullConfig.nearestCity)
|
||||
assertEquals(localPort(40002), fullConfig.rpcAddress)
|
||||
assertEquals(localPort(10001), fullConfig.p2pAddress)
|
||||
assertEquals(listOf("my.service"), fullConfig.extraAdvertisedServiceIds)
|
||||
@ -222,8 +216,7 @@ class NodeConfigTest {
|
||||
@Test
|
||||
fun `reading webserver configuration`() {
|
||||
val config = createConfig(
|
||||
legalName = "My Name",
|
||||
nearestCity = "Stockholm",
|
||||
legalName = myLegalName,
|
||||
p2pPort = 10001,
|
||||
rpcPort = 40002,
|
||||
webPort = 20001,
|
||||
@ -231,7 +224,7 @@ class NodeConfigTest {
|
||||
services = listOf("my.service"),
|
||||
users = listOf(user("jenny"))
|
||||
)
|
||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
||||
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
||||
|
||||
val nodeConfig = config.toFileConfig()
|
||||
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
||||
@ -247,7 +240,7 @@ class NodeConfigTest {
|
||||
|
||||
@Test
|
||||
fun `test moving`() {
|
||||
val config = createConfig(legalName = "My Name")
|
||||
val config = createConfig(legalName = myLegalName)
|
||||
|
||||
val elsewhere = baseDir / "elsewhere"
|
||||
val moved = config.moveTo(elsewhere)
|
||||
@ -257,8 +250,7 @@ class NodeConfigTest {
|
||||
}
|
||||
|
||||
private fun createConfig(
|
||||
legalName: String = "Unknown",
|
||||
nearestCity: String = "Nowhere",
|
||||
legalName: X500Name = X500Name("CN=Unknown,O=R3,OU=corda,L=Nowhere,C=UK"),
|
||||
p2pPort: Int = -1,
|
||||
rpcPort: Int = -1,
|
||||
webPort: Int = -1,
|
||||
@ -268,7 +260,6 @@ class NodeConfigTest {
|
||||
) = NodeConfig(
|
||||
baseDir,
|
||||
legalName = legalName,
|
||||
nearestCity = nearestCity,
|
||||
p2pPort = p2pPort,
|
||||
rpcPort = rpcPort,
|
||||
webPort = webPort,
|
||||
|
@ -1,7 +1,9 @@
|
||||
package net.corda.demobench.model
|
||||
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.nodeapi.User
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
@ -11,11 +13,13 @@ class NodeControllerTest {
|
||||
|
||||
private val baseDir: Path = Paths.get(".").toAbsolutePath()
|
||||
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
|
||||
fun `test unique nodes after validate`() {
|
||||
val data = NodeData()
|
||||
data.legalName.value = "Node 1"
|
||||
data.legalName.value = node1Name.toString()
|
||||
assertNotNull(controller.validate(data))
|
||||
assertNull(controller.validate(data))
|
||||
}
|
||||
@ -23,7 +27,7 @@ class NodeControllerTest {
|
||||
@Test
|
||||
fun `test unique key after validate`() {
|
||||
val data = NodeData()
|
||||
data.legalName.value = "Node 1"
|
||||
data.legalName.value = node1Name.toString()
|
||||
|
||||
assertFalse(controller.keyExists("node1"))
|
||||
controller.validate(data)
|
||||
@ -33,7 +37,7 @@ class NodeControllerTest {
|
||||
@Test
|
||||
fun `test matching name after validate`() {
|
||||
val data = NodeData()
|
||||
data.legalName.value = "Node 1"
|
||||
data.legalName.value = node1Name.toString()
|
||||
|
||||
assertFalse(controller.nameExists("Node 1"))
|
||||
assertFalse(controller.nameExists("Node1"))
|
||||
@ -47,7 +51,7 @@ class NodeControllerTest {
|
||||
@Test
|
||||
fun `test first validated node becomes network map`() {
|
||||
val data = NodeData()
|
||||
data.legalName.value = "Node 1"
|
||||
data.legalName.value = node1Name.toString()
|
||||
data.p2pPort.value = 100000
|
||||
|
||||
assertFalse(controller.hasNetworkMap())
|
||||
@ -57,14 +61,14 @@ class NodeControllerTest {
|
||||
|
||||
@Test
|
||||
fun `test register unique nodes`() {
|
||||
val config = createConfig(legalName = "Node 2")
|
||||
val config = createConfig(legalName = node2Name)
|
||||
assertTrue(controller.register(config))
|
||||
assertFalse(controller.register(config))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test unique key after register`() {
|
||||
val config = createConfig(legalName = "Node 2")
|
||||
val config = createConfig(legalName = node2Name)
|
||||
|
||||
assertFalse(controller.keyExists("node2"))
|
||||
controller.register(config)
|
||||
@ -73,7 +77,7 @@ class NodeControllerTest {
|
||||
|
||||
@Test
|
||||
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("Node2"))
|
||||
@ -86,7 +90,7 @@ class NodeControllerTest {
|
||||
|
||||
@Test
|
||||
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())
|
||||
|
||||
assertFalse(controller.hasNetworkMap())
|
||||
@ -96,8 +100,8 @@ class NodeControllerTest {
|
||||
|
||||
@Test
|
||||
fun `test register non-network-map node`() {
|
||||
val config = createConfig(legalName = "Node is not Network Map")
|
||||
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 10000)
|
||||
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(X500Name(DUMMY_NOTARY.name), 10000)
|
||||
assertFalse(config.isNetworkMap())
|
||||
|
||||
assertFalse(controller.hasNetworkMap())
|
||||
@ -151,7 +155,7 @@ class NodeControllerTest {
|
||||
|
||||
@Test
|
||||
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)
|
||||
|
||||
assertEquals(NodeState.STARTING, config.state)
|
||||
@ -162,8 +166,7 @@ class NodeControllerTest {
|
||||
}
|
||||
|
||||
private fun createConfig(
|
||||
legalName: String = "Unknown",
|
||||
nearestCity: String = "Nowhere",
|
||||
legalName: X500Name = X509Utilities.getDevX509Name("Unknown"),
|
||||
p2pPort: Int = -1,
|
||||
rpcPort: Int = -1,
|
||||
webPort: Int = -1,
|
||||
@ -173,7 +176,6 @@ class NodeControllerTest {
|
||||
) = NodeConfig(
|
||||
baseDir,
|
||||
legalName = legalName,
|
||||
nearestCity = nearestCity,
|
||||
p2pPort = p2pPort,
|
||||
rpcPort = rpcPort,
|
||||
webPort = webPort,
|
||||
|
Loading…
Reference in New Issue
Block a user