Merge pull request #1231 from corda/feature/vkolomeyko/os-merge

OS->Ent merge
This commit is contained in:
Viktor Kolomeyko 2018-07-09 21:17:46 +01:00 committed by GitHub
commit 13af5e00b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 225 additions and 119 deletions

View File

@ -54,7 +54,7 @@ class FlowsExecutionModeRpcTest : IntegrationTest() {
assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win"))
val user = User("mark", "dadada", setOf(invokeRpc("setFlowsDrainingModeEnabled"), invokeRpc("isFlowsDrainingModeEnabled"))) val user = User("mark", "dadada", setOf(invokeRpc("setFlowsDrainingModeEnabled"), invokeRpc("isFlowsDrainingModeEnabled")))
driver(DriverParameters(isDebug = true, inMemoryDB = false, startNodesInProcess = true)) { driver(DriverParameters(inMemoryDB = false, startNodesInProcess = true)) {
val nodeName = { val nodeName = {
val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow() val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
val nodeName = nodeHandle.nodeInfo.chooseIdentity().name val nodeName = nodeHandle.nodeInfo.chooseIdentity().name

View File

@ -13,13 +13,10 @@ package net.corda.core.identity
import com.google.common.collect.ImmutableSet import com.google.common.collect.ImmutableSet
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.internal.LegalNameValidator import net.corda.core.internal.LegalNameValidator
import net.corda.core.internal.toAttributesMap
import net.corda.core.internal.unspecifiedCountry import net.corda.core.internal.unspecifiedCountry
import net.corda.core.internal.x500Name import net.corda.core.internal.toX500Name
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.asn1.ASN1Encodable
import org.bouncycastle.asn1.ASN1ObjectIdentifier
import org.bouncycastle.asn1.x500.AttributeTypeAndValue
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x500.style.BCStyle import org.bouncycastle.asn1.x500.style.BCStyle
import java.util.* import java.util.*
import javax.security.auth.x500.X500Principal import javax.security.auth.x500.X500Principal
@ -96,29 +93,13 @@ data class CordaX500Name(val commonName: String?,
@JvmStatic @JvmStatic
fun build(principal: X500Principal): CordaX500Name { fun build(principal: X500Principal): CordaX500Name {
val x500Name = X500Name.getInstance(principal.encoded) val attrsMap = principal.toAttributesMap(supportedAttributes)
val attrsMap: Map<ASN1ObjectIdentifier, ASN1Encodable> = x500Name.rdNs
.flatMap { it.typesAndValues.asList() }
.groupBy(AttributeTypeAndValue::getType, AttributeTypeAndValue::getValue)
.mapValues {
require(it.value.size == 1) { "Duplicate attribute ${it.key}" }
it.value[0]
}
// Supported attribute checks.
(attrsMap.keys - supportedAttributes).let { unsupported ->
require(unsupported.isEmpty()) {
"The following attribute${if (unsupported.size > 1) "s are" else " is"} not supported in Corda: " +
unsupported.map { BCStyle.INSTANCE.oidToDisplayName(it) }
}
}
val CN = attrsMap[BCStyle.CN]?.toString() val CN = attrsMap[BCStyle.CN]?.toString()
val OU = attrsMap[BCStyle.OU]?.toString() val OU = attrsMap[BCStyle.OU]?.toString()
val O = attrsMap[BCStyle.O]?.toString() ?: throw IllegalArgumentException("Corda X.500 names must include an O attribute") val O = requireNotNull(attrsMap[BCStyle.O]?.toString()) { "Corda X.500 names must include an O attribute" }
val L = attrsMap[BCStyle.L]?.toString() ?: throw IllegalArgumentException("Corda X.500 names must include an L attribute") val L = requireNotNull(attrsMap[BCStyle.L]?.toString()) { "Corda X.500 names must include an L attribute" }
val ST = attrsMap[BCStyle.ST]?.toString() val ST = attrsMap[BCStyle.ST]?.toString()
val C = attrsMap[BCStyle.C]?.toString() ?: throw IllegalArgumentException("Corda X.500 names must include an C attribute") val C = requireNotNull(attrsMap[BCStyle.C]?.toString()) { "Corda X.500 names must include an C attribute" }
return CordaX500Name(CN, OU, O, L, ST, C) return CordaX500Name(CN, OU, O, L, ST, C)
} }
@ -132,7 +113,7 @@ data class CordaX500Name(val commonName: String?,
/** Return the [X500Principal] equivalent of this name. */ /** Return the [X500Principal] equivalent of this name. */
val x500Principal: X500Principal val x500Principal: X500Principal
get() { get() {
return _x500Principal ?: X500Principal(this.x500Name.encoded).also { _x500Principal = it } return _x500Principal ?: X500Principal(this.toX500Name().encoded).also { _x500Principal = it }
} }
override fun toString(): String = x500Principal.toString() override fun toString(): String = x500Principal.toString()

View File

@ -21,7 +21,6 @@ import net.corda.core.cordapp.CordappConfig
import net.corda.core.cordapp.CordappContext import net.corda.core.cordapp.CordappContext
import net.corda.core.crypto.* import net.corda.core.crypto.*
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.node.ServicesForResolution import net.corda.core.node.ServicesForResolution
import net.corda.core.serialization.* import net.corda.core.serialization.*
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
@ -30,9 +29,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.UntrustworthyData
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x500.X500NameBuilder
import org.bouncycastle.asn1.x500.style.BCStyle
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.MDC import org.slf4j.MDC
import rx.Observable import rx.Observable
@ -487,27 +483,6 @@ $trustAnchor""", e, this, e.index)
} }
} }
/**
* Return the underlying X.500 name from this Corda-safe X.500 name. These are guaranteed to have a consistent
* ordering, such that their `toString()` function returns the same value every time for the same [CordaX500Name].
*/
val CordaX500Name.x500Name: X500Name
get() {
return X500NameBuilder(BCStyle.INSTANCE).apply {
addRDN(BCStyle.C, country)
state?.let { addRDN(BCStyle.ST, it) }
addRDN(BCStyle.L, locality)
addRDN(BCStyle.O, organisation)
organisationUnit?.let { addRDN(BCStyle.OU, it) }
commonName?.let { addRDN(BCStyle.CN, it) }
}.build()
}
@Suppress("unused")
@VisibleForTesting
val CordaX500Name.Companion.unspecifiedCountry
get() = "ZZ"
inline fun <T : Any> T.signWithCert(signer: (SerializedBytes<T>) -> DigitalSignatureWithCert): SignedDataWithCert<T> { inline fun <T : Any> T.signWithCert(signer: (SerializedBytes<T>) -> DigitalSignatureWithCert): SignedDataWithCert<T> {
val serialised = serialize() val serialised = serialize()
return SignedDataWithCert(serialised, signer(serialised)) return SignedDataWithCert(serialised, signer(serialised))

View File

@ -0,0 +1,73 @@
@file:KeepForDJVM
package net.corda.core.internal
import net.corda.core.KeepForDJVM
import net.corda.core.identity.CordaX500Name
import org.bouncycastle.asn1.ASN1Encodable
import org.bouncycastle.asn1.ASN1ObjectIdentifier
import org.bouncycastle.asn1.x500.AttributeTypeAndValue
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x500.X500NameBuilder
import org.bouncycastle.asn1.x500.style.BCStyle
import javax.security.auth.x500.X500Principal
/**
* Return the underlying X.500 name from this Corda-safe X.500 name. These are guaranteed to have a consistent
* ordering, such that their `toString()` function returns the same value every time for the same [CordaX500Name].
*/
fun CordaX500Name.toX500Name(): X500Name {
return X500NameBuilder(BCStyle.INSTANCE).apply {
addRDN(BCStyle.C, country)
state?.let { addRDN(BCStyle.ST, it) }
addRDN(BCStyle.L, locality)
addRDN(BCStyle.O, organisation)
organisationUnit?.let { addRDN(BCStyle.OU, it) }
commonName?.let { addRDN(BCStyle.CN, it) }
}.build()
}
/**
* Converts the X500Principal instance to the X500Name object.
*/
fun X500Principal.toX500Name(): X500Name = X500Name.getInstance(this.encoded)
/**
* Transforms the X500Principal to the attributes map.
*
* @param supportedAttributes list of supported attributes. If empty, it accepts all the attributes.
*
* @return attributes map for this principal
* @throws IllegalArgumentException if this principal consists of duplicated attributes or the attribute is not supported.
*
*/
fun X500Principal.toAttributesMap(supportedAttributes: Set<ASN1ObjectIdentifier> = emptySet()): Map<ASN1ObjectIdentifier, ASN1Encodable> {
val x500Name = this.toX500Name()
val attrsMap: Map<ASN1ObjectIdentifier, ASN1Encodable> = x500Name.rdNs
.flatMap { it.typesAndValues.asList() }
.groupBy(AttributeTypeAndValue::getType, AttributeTypeAndValue::getValue)
.mapValues {
require(it.value.size == 1) { "Duplicate attribute ${it.key}" }
it.value[0]
}
if (supportedAttributes.isNotEmpty()) {
(attrsMap.keys - supportedAttributes).let { unsupported ->
require(unsupported.isEmpty()) {
"The following attribute${if (unsupported.size > 1) "s are" else " is"} not supported in Corda: " +
unsupported.map { BCStyle.INSTANCE.oidToDisplayName(it) }
}
}
}
return attrsMap
}
/**
* Checks equality between the two X500Principal instances ignoring the ordering of the X500Name parts.
*/
fun X500Principal.isEquivalentTo(other: X500Principal): Boolean {
return toAttributesMap() == other.toAttributesMap()
}
@VisibleForTesting
val CordaX500Name.Companion.unspecifiedCountry
get() = "ZZ"

View File

@ -0,0 +1,26 @@
package net.corda.core.identity
import net.corda.core.internal.isEquivalentTo
import org.junit.Test
import javax.security.auth.x500.X500Principal
import kotlin.test.assertTrue
class X500UtilsTest {
@Test
fun `X500Principal equalX500NameParts matches regardless the order`() {
// given
val orderingA = "O=Bank A, OU=Organisation Unit, L=New York, C=US"
val orderingB = "OU=Organisation Unit, O=Bank A, L=New York, C=US"
val orderingC = "L=New York, O=Bank A, C=US, OU=Organisation Unit"
// when
val principalA = X500Principal(orderingA)
val principalB = X500Principal(orderingB)
val principalC = X500Principal(orderingC)
// then
assertTrue { principalA.isEquivalentTo(principalB) }
assertTrue { principalB.isEquivalentTo(principalC) }
}
}

View File

@ -1,6 +1,8 @@
Network Map Network map
=========== ===========
.. contents::
The network map is a collection of signed ``NodeInfo`` objects. Each NodeInfo is signed by the node it represents and The network map is a collection of signed ``NodeInfo`` objects. Each NodeInfo is signed by the node it represents and
thus cannot be tampered with. It forms the set of reachable nodes in a compatibility zone. A node can receive these thus cannot be tampered with. It forms the set of reachable nodes in a compatibility zone. A node can receive these
objects from two sources: objects from two sources:

View File

@ -3,6 +3,8 @@
Setting up a Corda network Setting up a Corda network
========================== ==========================
.. contents::
A Corda network consists of a number of machines running nodes. These nodes communicate using persistent protocols in A Corda network consists of a number of machines running nodes. These nodes communicate using persistent protocols in
order to create and validate transactions. order to create and validate transactions.

View File

@ -14,7 +14,7 @@ import net.corda.core.crypto.Crypto
import net.corda.core.crypto.Crypto.generateKeyPair import net.corda.core.crypto.Crypto.generateKeyPair
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.x500Name import net.corda.core.internal.toX500Name
import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.nodeapi.internal.crypto.* import net.corda.nodeapi.internal.crypto.*
import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralName
@ -93,7 +93,7 @@ fun createDevNetworkMapCa(rootCa: CertificateAndKeyPair = DEV_ROOT_CA): Certific
fun createDevNodeCa(intermediateCa: CertificateAndKeyPair, fun createDevNodeCa(intermediateCa: CertificateAndKeyPair,
legalName: CordaX500Name, legalName: CordaX500Name,
nodeKeyPair: KeyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)): CertificateAndKeyPair { nodeKeyPair: KeyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)): CertificateAndKeyPair {
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.x500Name))), arrayOf()) val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.toX500Name()))), arrayOf())
val cert = X509Utilities.createCertificate( val cert = X509Utilities.createCertificate(
CertificateType.NODE_CA, CertificateType.NODE_CA,
intermediateCa.certificate, intermediateCa.certificate,

View File

@ -73,7 +73,7 @@ class BootTests : IntegrationTest() {
@Test @Test
fun `double node start doesn't write into log file`() { fun `double node start doesn't write into log file`() {
driver(DriverParameters(isDebug = true)) { driver {
val alice = startNode(providedName = ALICE_NAME).get() val alice = startNode(providedName = ALICE_NAME).get()
val logFolder = alice.baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME val logFolder = alice.baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME
val logFile = logFolder.list { it.filter { it.fileName.toString().endsWith(".log") }.findAny().get() } val logFile = logFolder.list { it.filter { it.fileName.toString().endsWith(".log") }.findAny().get() }

View File

@ -38,7 +38,7 @@ class NodeUnloadHandlerTests : IntegrationTest() {
@Test @Test
fun `should be able to register run on stop lambda`() { fun `should be able to register run on stop lambda`() {
driver(DriverParameters(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.node"), isDebug = true)) { driver(DriverParameters(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.node"))) {
startNode(providedName = DUMMY_BANK_A_NAME).getOrThrow() startNode(providedName = DUMMY_BANK_A_NAME).getOrThrow()
// just want to fall off the end of this for the mo... // just want to fall off the end of this for the mo...
} }

View File

@ -46,7 +46,7 @@ class FlowRetryTest : IntegrationTest() {
val numSessions = 2 val numSessions = 2
val numIterations = 10 val numIterations = 10
val user = User("mark", "dadada", setOf(Permissions.startFlow<InitiatorFlow>())) val user = User("mark", "dadada", setOf(Permissions.startFlow<InitiatorFlow>()))
val result: Any? = driver(DriverParameters(isDebug = true, startNodesInProcess = isQuasarAgentSpecified(), val result: Any? = driver(DriverParameters(startNodesInProcess = isQuasarAgentSpecified(),
portAllocation = RandomFree)) { portAllocation = RandomFree)) {
val nodeAHandle = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val nodeAHandle = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()

View File

@ -67,7 +67,7 @@ class FlowsDrainingModeContentionTest : IntegrationTest() {
@Test @Test
fun `draining mode does not deadlock with acks between 2 nodes`() { fun `draining mode does not deadlock with acks between 2 nodes`() {
val message = "Ground control to Major Tom" val message = "Ground control to Major Tom"
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = portAllocation, extraCordappPackagesToScan = listOf(MessageState::class.packageName))) { driver(DriverParameters(startNodesInProcess = true, portAllocation = portAllocation, extraCordappPackagesToScan = listOf(MessageState::class.packageName))) {
val nodeA = startNode(providedName = ALICE_NAME, rpcUsers = users).getOrThrow() val nodeA = startNode(providedName = ALICE_NAME, rpcUsers = users).getOrThrow()
val nodeB = startNode(providedName = BOB_NAME, rpcUsers = users).getOrThrow() val nodeB = startNode(providedName = BOB_NAME, rpcUsers = users).getOrThrow()

View File

@ -69,7 +69,7 @@ class P2PFlowsDrainingModeTest : IntegrationTest() {
@Test @Test
fun `flows draining mode suspends consumption of initial session messages`() { fun `flows draining mode suspends consumption of initial session messages`() {
driver(DriverParameters(isDebug = true, startNodesInProcess = false, portAllocation = portAllocation)) { driver(DriverParameters(startNodesInProcess = false, portAllocation = portAllocation)) {
val initiatedNode = startNode(providedName = ALICE_NAME).getOrThrow() val initiatedNode = startNode(providedName = ALICE_NAME).getOrThrow()
val initiating = startNode(providedName = BOB_NAME, rpcUsers = users).getOrThrow().rpc val initiating = startNode(providedName = BOB_NAME, rpcUsers = users).getOrThrow().rpc
@ -101,7 +101,7 @@ class P2PFlowsDrainingModeTest : IntegrationTest() {
@Test @Test
fun `clean shutdown by draining`() { fun `clean shutdown by draining`() {
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = portAllocation)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = portAllocation)) {
val nodeA = startNode(providedName = ALICE_NAME, rpcUsers = users).getOrThrow() val nodeA = startNode(providedName = ALICE_NAME, rpcUsers = users).getOrThrow()
val nodeB = startNode(providedName = BOB_NAME, rpcUsers = users).getOrThrow() val nodeB = startNode(providedName = BOB_NAME, rpcUsers = users).getOrThrow()

View File

@ -45,7 +45,7 @@ class RpcFlowsDrainingModeTest : IntegrationTest() {
@Test @Test
fun `flows draining mode rejects start flows commands through rpc`() { fun `flows draining mode rejects start flows commands through rpc`() {
driver(DriverParameters(isDebug = true, startNodesInProcess = false, portAllocation = portAllocation)) { driver(DriverParameters(startNodesInProcess = false, portAllocation = portAllocation)) {
startNode(rpcUsers = users).getOrThrow().rpc.apply { startNode(rpcUsers = users).getOrThrow().rpc.apply {

View File

@ -57,7 +57,7 @@ class NodeStatePersistenceTests : IntegrationTest() {
fun `persistent state survives node restart`() { fun `persistent state survives node restart`() {
val user = User("mark", "dadada", setOf(startFlow<SendMessageFlow>(), invokeRpc("vaultQuery"))) val user = User("mark", "dadada", setOf(startFlow<SendMessageFlow>(), invokeRpc("vaultQuery")))
val message = Message("Hello world!") val message = Message("Hello world!")
val stateAndRef: StateAndRef<MessageState>? = driver(DriverParameters(isDebug = true, inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), val stateAndRef: StateAndRef<MessageState>? = driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(),
portAllocation = RandomFree, extraCordappPackagesToScan = listOf(MessageState::class.packageName))) { portAllocation = RandomFree, extraCordappPackagesToScan = listOf(MessageState::class.packageName))) {
val nodeName = { val nodeName = {
val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow() val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
@ -90,7 +90,7 @@ class NodeStatePersistenceTests : IntegrationTest() {
val user = User("mark", "dadada", setOf(startFlow<SendMessageFlow>(), invokeRpc("vaultQuery"))) val user = User("mark", "dadada", setOf(startFlow<SendMessageFlow>(), invokeRpc("vaultQuery")))
val message = Message("Hello world!") val message = Message("Hello world!")
val stateAndRef: StateAndRef<MessageState>? = driver(DriverParameters(isDebug = true, inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), portAllocation = RandomFree, extraCordappPackagesToScan = listOf(MessageState::class.packageName))) { val stateAndRef: StateAndRef<MessageState>? = driver(DriverParameters(inMemoryDB = false, startNodesInProcess = isQuasarAgentSpecified(), portAllocation = RandomFree, extraCordappPackagesToScan = listOf(MessageState::class.packageName))) {
val nodeName = { val nodeName = {
val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow() val nodeHandle = startNode(rpcUsers = listOf(user)).getOrThrow()
val nodeName = nodeHandle.nodeInfo.singleIdentity().name val nodeName = nodeHandle.nodeInfo.singleIdentity().name

View File

@ -70,7 +70,7 @@ class RpcSslTest : IntegrationTest() {
val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert) val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert)
val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password") val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password")
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
val node = startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow() val node = startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow()
val client = CordaRPCClient.createWithSsl(node.rpcAddress, sslConfiguration = clientSslOptions) val client = CordaRPCClient.createWithSsl(node.rpcAddress, sslConfiguration = clientSslOptions)
val connection = client.start(user.username, user.password) val connection = client.start(user.username, user.password)
@ -108,7 +108,7 @@ class RpcSslTest : IntegrationTest() {
val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert1) val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert1)
val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password") val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password")
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
val node = startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow() val node = startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow()
Assertions.assertThatThrownBy { Assertions.assertThatThrownBy {
val connection = CordaRPCClient.createWithSsl(node.rpcAddress, sslConfiguration = clientSslOptions).start(user.username, user.password) val connection = CordaRPCClient.createWithSsl(node.rpcAddress, sslConfiguration = clientSslOptions).start(user.username, user.password)
@ -128,7 +128,7 @@ class RpcSslTest : IntegrationTest() {
fun `RPC client not using ssl can run commands`() { fun `RPC client not using ssl can run commands`() {
val user = User("mark", "dadada", setOf(all())) val user = User("mark", "dadada", setOf(all()))
var successful = false var successful = false
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
val node = startNode(rpcUsers = listOf(user)).getOrThrow() val node = startNode(rpcUsers = listOf(user)).getOrThrow()
val connection = CordaRPCClient(node.rpcAddress).start(user.username, user.password) val connection = CordaRPCClient(node.rpcAddress).start(user.username, user.password)
connection.proxy.apply { connection.proxy.apply {
@ -148,7 +148,7 @@ class RpcSslTest : IntegrationTest() {
val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert) val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert)
val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password") val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password")
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
val node = startNode(customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow() val node = startNode(customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow()
val client = CordaRPCClient.createWithSsl(node.rpcAddress, sslConfiguration = clientSslOptions) val client = CordaRPCClient.createWithSsl(node.rpcAddress, sslConfiguration = clientSslOptions)

View File

@ -70,7 +70,7 @@ class HardRestartTest : IntegrationTest() {
@Test @Test
fun restartShortPingPongFlowRandomly() { fun restartShortPingPongFlowRandomly() {
val demoUser = User("demo", "demo", setOf(Permissions.startFlow<Ping>(), Permissions.all())) val demoUser = User("demo", "demo", setOf(Permissions.startFlow<Ping>(), Permissions.all()))
driver(DriverParameters(isDebug = true, startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) { driver(DriverParameters(startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) {
val (a, b) = listOf( val (a, b) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")),
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000")) startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000"))
@ -102,7 +102,7 @@ class HardRestartTest : IntegrationTest() {
@Test @Test
fun restartLongPingPongFlowRandomly() { fun restartLongPingPongFlowRandomly() {
val demoUser = User("demo", "demo", setOf(Permissions.startFlow<Ping>(), Permissions.all())) val demoUser = User("demo", "demo", setOf(Permissions.startFlow<Ping>(), Permissions.all()))
driver(DriverParameters(isDebug = true, startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) { driver(DriverParameters(startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) {
val (a, b) = listOf( val (a, b) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")),
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000")) startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000"))
@ -134,7 +134,7 @@ class HardRestartTest : IntegrationTest() {
@Test @Test
fun softRestartLongPingPongFlowRandomly() { fun softRestartLongPingPongFlowRandomly() {
val demoUser = User("demo", "demo", setOf(Permissions.startFlow<Ping>(), Permissions.all())) val demoUser = User("demo", "demo", setOf(Permissions.startFlow<Ping>(), Permissions.all()))
driver(DriverParameters(isDebug = true, startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) { driver(DriverParameters(startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) {
val (a, b) = listOf( val (a, b) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")),
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000")) startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000"))
@ -210,7 +210,7 @@ class HardRestartTest : IntegrationTest() {
@Test @Test
fun restartRecursiveFlowRandomly() { fun restartRecursiveFlowRandomly() {
val demoUser = User("demo", "demo", setOf(Permissions.startFlow<RecursiveA>(), Permissions.all())) val demoUser = User("demo", "demo", setOf(Permissions.startFlow<RecursiveA>(), Permissions.all()))
driver(DriverParameters(isDebug = true, startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) { driver(DriverParameters(startNodesInProcess = false, inMemoryDB = false, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))) {
val (a, b) = listOf( val (a, b) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:30000")),
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000")) startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser), customOverrides = mapOf("p2pAddress" to "localhost:40000"))

View File

@ -15,7 +15,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.copyTo import net.corda.core.internal.copyTo
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.exists import net.corda.core.internal.exists
import net.corda.core.internal.x500Name import net.corda.core.internal.toX500Name
import net.corda.nodeapi.RPCApi import net.corda.nodeapi.RPCApi
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_P2P_USER import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_P2P_USER
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER
@ -109,7 +109,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
val clientKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val clientKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
// Set name constrain to the legal name. // Set name constrain to the legal name.
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.x500Name))), arrayOf()) val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.toX500Name()))), arrayOf())
val clientCACert = X509Utilities.createCertificate( val clientCACert = X509Utilities.createCertificate(
CertificateType.INTERMEDIATE_CA, CertificateType.INTERMEDIATE_CA,
DEV_INTERMEDIATE_CA.certificate, DEV_INTERMEDIATE_CA.certificate,

View File

@ -14,6 +14,7 @@
import com.typesafe.config.*; import com.typesafe.config.*;
import sun.misc.Signal; import sun.misc.Signal;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -53,7 +54,7 @@ public class CordaCaplet extends Capsule {
Config nodeConfig = ConfigFactory.parseFile(configFile, parseOptions); Config nodeConfig = ConfigFactory.parseFile(configFile, parseOptions);
return baseDirectoryConfig.withFallback(nodeConfig).withFallback(defaultConfig).resolve(); return baseDirectoryConfig.withFallback(nodeConfig).withFallback(defaultConfig).resolve();
} catch (ConfigException e) { } catch (ConfigException e) {
log(LOG_QUIET, e); log(LOG_DEBUG, e);
return ConfigFactory.empty(); return ConfigFactory.empty();
} }
} }

View File

@ -31,6 +31,19 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
private val logger = contextLogger() private val logger = contextLogger()
} }
sealed class Error(message: String) : Exception(message) {
class ParamsNotConfigured : Error("Couldn't find network parameters file and compatibility zone wasn't configured/isn't reachable.")
class NetworkMapNotConfigured : Error("Node hasn't been configured to connect to a network map from which to get the network parameters.")
class OldParamsAndUpdate : Error(
"Both network parameters and network parameters update files don't match" +
"parameters advertised by network map. Please update node to use correct network parameters file."
)
class OldParams(previousParametersHash: SecureHash, advertisedParametersHash: SecureHash) : Error(
"Node uses parameters with hash: $previousParametersHash but network map is advertising: " +
"$advertisedParametersHash. Please update node to use correct network parameters file."
)
}
private data class NetworkParamsAndHash(val networkParameters: NetworkParameters, val hash: SecureHash) private data class NetworkParamsAndHash(val networkParameters: NetworkParameters, val hash: SecureHash)
private val networkParamsFile = baseDirectory / NETWORK_PARAMS_FILE_NAME private val networkParamsFile = baseDirectory / NETWORK_PARAMS_FILE_NAME
private val parametersUpdateFile = baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME private val parametersUpdateFile = baseDirectory / NETWORK_PARAMS_UPDATE_FILE_NAME
@ -63,7 +76,7 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash) readParametersUpdate(advertisedParametersHash, signedParametersFromFile.raw.hash)
} }
} else { // No compatibility zone configured. Node should proceed with parameters from file. } else { // No compatibility zone configured. Node should proceed with parameters from file.
signedParametersFromFile ?: throw IllegalArgumentException("Couldn't find network parameters file and compatibility zone wasn't configured/isn't reachable") signedParametersFromFile ?: throw Error.ParamsNotConfigured()
} }
logger.info("Loaded network parameters: $parameters") logger.info("Loaded network parameters: $parameters")
return NetworkParamsAndHash(parameters.verifiedNetworkMapCert(trustRoot), parameters.raw.hash) return NetworkParamsAndHash(parameters.verifiedNetworkMapCert(trustRoot), parameters.raw.hash)
@ -71,15 +84,11 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
private fun readParametersUpdate(advertisedParametersHash: SecureHash, previousParametersHash: SecureHash): SignedNetworkParameters { private fun readParametersUpdate(advertisedParametersHash: SecureHash, previousParametersHash: SecureHash): SignedNetworkParameters {
if (!parametersUpdateFile.exists()) { if (!parametersUpdateFile.exists()) {
throw IllegalArgumentException("Node uses parameters with hash: $previousParametersHash " + throw Error.OldParams(previousParametersHash, advertisedParametersHash)
"but network map is advertising: $advertisedParametersHash.\n" +
"Please update node to use correct network parameters file.")
} }
val signedUpdatedParameters = parametersUpdateFile.readObject<SignedNetworkParameters>() val signedUpdatedParameters = parametersUpdateFile.readObject<SignedNetworkParameters>()
if (signedUpdatedParameters.raw.hash != advertisedParametersHash) { if (signedUpdatedParameters.raw.hash != advertisedParametersHash) {
throw IllegalArgumentException("Both network parameters and network parameters update files don't match" + throw Error.OldParamsAndUpdate()
"parameters advertised by network map.\n" +
"Please update node to use correct network parameters file.")
} }
parametersUpdateFile.moveTo(networkParamsFile, StandardCopyOption.REPLACE_EXISTING) parametersUpdateFile.moveTo(networkParamsFile, StandardCopyOption.REPLACE_EXISTING)
logger.info("Scheduled update to network parameters has occurred - node now updated to these new parameters.") logger.info("Scheduled update to network parameters has occurred - node now updated to these new parameters.")
@ -89,9 +98,7 @@ class NetworkParametersReader(private val trustRoot: X509Certificate,
// Used only when node joins for the first time. // Used only when node joins for the first time.
private fun downloadParameters(parametersHash: SecureHash): SignedNetworkParameters { private fun downloadParameters(parametersHash: SecureHash): SignedNetworkParameters {
logger.info("No network-parameters file found. Expecting network parameters to be available from the network map.") logger.info("No network-parameters file found. Expecting network parameters to be available from the network map.")
val networkMapClient = checkNotNull(networkMapClient) { val networkMapClient = networkMapClient ?: throw Error.NetworkMapNotConfigured()
"Node hasn't been configured to connect to a network map from which to get the network parameters"
}
val signedParams = networkMapClient.getNetworkParameters(parametersHash) val signedParams = networkMapClient.getNetworkParameters(parametersHash)
signedParams.serialize().open().copyTo(baseDirectory / NETWORK_PARAMS_FILE_NAME) signedParams.serialize().open().copyTo(baseDirectory / NETWORK_PARAMS_FILE_NAME)
return signedParams return signedParams

View File

@ -21,12 +21,7 @@ import net.corda.core.internal.*
import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.utilities.Try import net.corda.core.utilities.Try
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.CmdLineOptions import net.corda.node.*
import net.corda.node.NodeArgsParser
import net.corda.node.NodeRegistrationOption
import net.corda.node.SerialFilter
import net.corda.node.VersionInfo
import net.corda.node.defaultSerialFilter
import net.corda.node.internal.cordapp.MultipleCordappsForFlowException import net.corda.node.internal.cordapp.MultipleCordappsForFlowException
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NodeConfigurationImpl import net.corda.node.services.config.NodeConfigurationImpl
@ -36,9 +31,9 @@ import net.corda.node.services.transactions.bftSMaRtSerialFilter
import net.corda.node.utilities.createKeyPairAndSelfSignedTLSCertificate import net.corda.node.utilities.createKeyPairAndSelfSignedTLSCertificate
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
import net.corda.node.utilities.registration.NodeRegistrationHelper import net.corda.node.utilities.registration.NodeRegistrationHelper
import net.corda.node.utilities.registration.UnableToRegisterNodeWithDoormanException
import net.corda.node.utilities.saveToKeyStore import net.corda.node.utilities.saveToKeyStore
import net.corda.node.utilities.saveToTrustStore import net.corda.node.utilities.saveToTrustStore
import net.corda.node.utilities.registration.UnableToRegisterNodeWithDoormanException
import net.corda.nodeapi.internal.addShutdownHook import net.corda.nodeapi.internal.addShutdownHook
import net.corda.nodeapi.internal.config.UnknownConfigurationKeysException import net.corda.nodeapi.internal.config.UnknownConfigurationKeysException
import net.corda.nodeapi.internal.persistence.DatabaseMigrationException import net.corda.nodeapi.internal.persistence.DatabaseMigrationException
@ -171,6 +166,9 @@ open class NodeStartup(val args: Array<String>) {
} catch (e: CheckpointIncompatibleException) { } catch (e: CheckpointIncompatibleException) {
logger.error(e.message) logger.error(e.message)
return false return false
} catch (e: NetworkParametersReader.Error) {
logger.error(e.message)
return false
} catch (e: Exception) { } catch (e: Exception) {
if (e is Errors.NativeIoException && e.message?.contains("Address already in use") == true) { if (e is Errors.NativeIoException && e.message?.contains("Address already in use") == true) {
logger.error("One of the ports required by the Corda node is already in use.") logger.error("One of the ports required by the Corda node is already in use.")

View File

@ -35,6 +35,7 @@ import java.security.PublicKey
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import java.time.Duration import java.time.Duration
import javax.naming.ServiceUnavailableException import javax.naming.ServiceUnavailableException
import javax.security.auth.x500.X500Principal
/** /**
* Helper for managing the node registration process, which checks for any existing certificates and requests them if * Helper for managing the node registration process, which checks for any existing certificates and requests them if
@ -53,13 +54,14 @@ open class NetworkRegistrationHelper(private val config: SSLConfiguration,
companion object { companion object {
const val SELF_SIGNED_PRIVATE_KEY = "Self Signed Private Key" const val SELF_SIGNED_PRIVATE_KEY = "Self Signed Private Key"
val logger = contextLogger()
} }
private val requestIdStore = config.certificatesDirectory / "certificate-request-id.txt" private val requestIdStore = config.certificatesDirectory / "certificate-request-id.txt"
// TODO: Use different password for private key. // TODO: Use different password for private key.
private val privateKeyPassword = config.keyStorePassword private val privateKeyPassword = config.keyStorePassword
private val rootTrustStore: X509KeyStore private val rootTrustStore: X509KeyStore
private val rootCert: X509Certificate protected val rootCert: X509Certificate
init { init {
require(networkRootTrustStorePath.exists()) { require(networkRootTrustStorePath.exists()) {
@ -88,6 +90,13 @@ open class NetworkRegistrationHelper(private val config: SSLConfiguration,
println("Certificate already exists, Corda node will now terminate...") println("Certificate already exists, Corda node will now terminate...")
return return
} }
val tlsCrlIssuerCert = validateAndGetTlsCrlIssuerCert()
if (tlsCrlIssuerCert == null && isTlsCrlIssuerCertRequired()) {
System.err.println("""tlsCrlIssuerCert config does not match the root certificate issuer and nor is there any other certificate in the trust store with a matching issuer.
| Please make sure the config is correct or that the correct certificate for the CRL issuer is added to the node's trust store.
| The node will now terminate.""".trimMargin())
throw IllegalArgumentException("TLS CRL issuer certificate not found in the trust store.")
}
val keyPair = nodeKeyStore.loadOrCreateKeyPair(SELF_SIGNED_PRIVATE_KEY) val keyPair = nodeKeyStore.loadOrCreateKeyPair(SELF_SIGNED_PRIVATE_KEY)
@ -104,7 +113,7 @@ open class NetworkRegistrationHelper(private val config: SSLConfiguration,
} }
validateCertificates(keyPair.public, certificates) validateCertificates(keyPair.public, certificates)
storePrivateKeyWithCertificates(nodeKeyStore, keyPair, certificates, keyAlias) storePrivateKeyWithCertificates(nodeKeyStore, keyPair, certificates, keyAlias)
onSuccess(keyPair, certificates) onSuccess(keyPair, certificates, tlsCrlIssuerCert?.let { it.subjectX500Principal.toX500Name() })
// All done, clean up temp files. // All done, clean up temp files.
requestIdStore.deleteIfExists() requestIdStore.deleteIfExists()
} }
@ -226,7 +235,11 @@ open class NetworkRegistrationHelper(private val config: SSLConfiguration,
} }
} }
protected open fun onSuccess(nodeCAKeyPair: KeyPair, certificates: List<X509Certificate>) {} protected open fun onSuccess(nodeCAKeyPair: KeyPair, certificates: List<X509Certificate>, tlsCrlCertificateIssuer: X500Name?) {}
protected open fun validateAndGetTlsCrlIssuerCert(): X509Certificate? = null
protected open fun isTlsCrlIssuerCertRequired(): Boolean = false
} }
class UnableToRegisterNodeWithDoormanException : IOException() class UnableToRegisterNodeWithDoormanException : IOException()
@ -246,12 +259,12 @@ class NodeRegistrationHelper(private val config: NodeConfiguration, certService:
val logger = contextLogger() val logger = contextLogger()
} }
override fun onSuccess(nodeCAKeyPair: KeyPair, certificates: List<X509Certificate>) { override fun onSuccess(nodeCAKeyPair: KeyPair, certificates: List<X509Certificate>, tlsCrlCertificateIssuer: X500Name?) {
createSSLKeystore(nodeCAKeyPair, certificates) createSSLKeystore(nodeCAKeyPair, certificates, tlsCrlCertificateIssuer)
createTruststore(certificates.last()) createTruststore(certificates.last())
} }
private fun createSSLKeystore(nodeCAKeyPair: KeyPair, certificates: List<X509Certificate>) { private fun createSSLKeystore(nodeCAKeyPair: KeyPair, certificates: List<X509Certificate>, tlsCertCrlIssuer: X500Name?) {
config.loadSslKeyStore(createNew = true).update { config.loadSslKeyStore(createNew = true).update {
println("Generating SSL certificate for node messaging service.") println("Generating SSL certificate for node messaging service.")
val sslKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val sslKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
@ -262,7 +275,7 @@ class NodeRegistrationHelper(private val config: NodeConfiguration, certService:
config.myLegalName.x500Principal, config.myLegalName.x500Principal,
sslKeyPair.public, sslKeyPair.public,
crlDistPoint = config.tlsCertCrlDistPoint?.toString(), crlDistPoint = config.tlsCertCrlDistPoint?.toString(),
crlIssuer = if (config.tlsCertCrlIssuer != null) X500Name(config.tlsCertCrlIssuer) else null) crlIssuer = tlsCertCrlIssuer)
logger.info("Generated TLS certificate: $sslCert") logger.info("Generated TLS certificate: $sslCert")
setPrivateKey(CORDA_CLIENT_TLS, sslKeyPair.private, listOf(sslCert) + certificates) setPrivateKey(CORDA_CLIENT_TLS, sslKeyPair.private, listOf(sslCert) + certificates)
} }
@ -278,6 +291,37 @@ class NodeRegistrationHelper(private val config: NodeConfiguration, certService:
} }
println("Node trust store stored in ${config.trustStoreFile}.") println("Node trust store stored in ${config.trustStoreFile}.")
} }
override fun validateAndGetTlsCrlIssuerCert(): X509Certificate? {
config.tlsCertCrlIssuer ?: return null
val tlsCertCrlIssuerPrincipal = X500Principal(config.tlsCertCrlIssuer)
if (principalMatchesCertificatePrincipal(tlsCertCrlIssuerPrincipal, rootCert)) {
return rootCert
}
return if (config.trustStoreFile.exists()) {
findMatchingCertificate(tlsCertCrlIssuerPrincipal, config.loadTrustStore())
} else {
null
}
}
override fun isTlsCrlIssuerCertRequired(): Boolean {
return !config.tlsCertCrlIssuer.isNullOrEmpty()
}
private fun findMatchingCertificate(principal: X500Principal, trustStore: X509KeyStore): X509Certificate? {
trustStore.aliases().forEach {
val certificate = trustStore.getCertificate(it)
if (principalMatchesCertificatePrincipal(principal, certificate)) {
return certificate
}
}
return null
}
private fun principalMatchesCertificatePrincipal(principal: X500Principal, certificate: X509Certificate): Boolean {
return certificate.subjectX500Principal.isEquivalentTo(principal)
}
} }
private class FixedPeriodLimitedRetrialStrategy(times: Int, private val period: Duration) : (Duration?) -> Duration? { private class FixedPeriodLimitedRetrialStrategy(times: Int, private val period: Duration) : (Duration?) -> Duration? {

View File

@ -22,10 +22,9 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.CertRole import net.corda.core.internal.CertRole
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.internal.x500Name import net.corda.core.internal.toX500Name
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.node.NodeRegistrationOption import net.corda.node.NodeRegistrationOption
import net.corda.node.VersionInfo
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.DevIdentityGenerator import net.corda.nodeapi.internal.DevIdentityGenerator
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
@ -71,6 +70,7 @@ class NetworkRegistrationHelperTest {
doReturn("").whenever(it).emailAddress doReturn("").whenever(it).emailAddress
doReturn(null).whenever(it).tlsCertCrlDistPoint doReturn(null).whenever(it).tlsCertCrlDistPoint
doReturn(null).whenever(it).tlsCertCrlIssuer doReturn(null).whenever(it).tlsCertCrlIssuer
doReturn(true).whenever(it).crlCheckSoftFail
} }
} }
@ -192,7 +192,7 @@ class NetworkRegistrationHelperTest {
rootAndIntermediateCA: Pair<CertificateAndKeyPair, CertificateAndKeyPair> = createDevIntermediateCaCertPath()): List<X509Certificate> { rootAndIntermediateCA: Pair<CertificateAndKeyPair, CertificateAndKeyPair> = createDevIntermediateCaCertPath()): List<X509Certificate> {
val (rootCa, intermediateCa) = rootAndIntermediateCA val (rootCa, intermediateCa) = rootAndIntermediateCA
val nameConstraints = if (type == CertificateType.NODE_CA) { val nameConstraints = if (type == CertificateType.NODE_CA) {
NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.x500Name))), arrayOf()) NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.toX500Name()))), arrayOf())
} else { } else {
null null
} }

View File

@ -39,7 +39,7 @@ class AttachmentDemoTest : IntegrationTest() {
@Test @Test
fun `attachment demo using a 10MB zip file`() { fun `attachment demo using a 10MB zip file`() {
val numOfExpectedBytes = 10_000_000 val numOfExpectedBytes = 10_000_000
driver(DriverParameters(isDebug = true, portAllocation = PortAllocation.Incremental(20000), startNodesInProcess = true)) { driver(DriverParameters(portAllocation = PortAllocation.Incremental(20000), startNodesInProcess = true)) {
val demoUser = listOf(User("demo", "demo", setOf(all()))) val demoUser = listOf(User("demo", "demo", setOf(all())))
val (nodeA, nodeB) = listOf( val (nodeA, nodeB) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"),

View File

@ -23,7 +23,7 @@ import net.corda.testing.node.User
*/ */
fun main(args: Array<String>) { fun main(args: Array<String>) {
val demoUser = listOf(User("demo", "demo", setOf("StartFlow.net.corda.flows.FinalityFlow"))) val demoUser = listOf(User("demo", "demo", setOf("StartFlow.net.corda.flows.FinalityFlow")))
driver(DriverParameters(isDebug = true, driverDirectory = "build" / "attachment-demo-nodes", waitForAllNodesToFinish = true)) { driver(DriverParameters(driverDirectory = "build" / "attachment-demo-nodes", waitForAllNodesToFinish = true)) {
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser) startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser)
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = demoUser) startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = demoUser)
} }

View File

@ -47,7 +47,7 @@ class BankOfCordaRPCClientTest : IntegrationTest() {
invokeRpc(CordaRPCOps::wellKnownPartyFromX500Name), invokeRpc(CordaRPCOps::wellKnownPartyFromX500Name),
invokeRpc(CordaRPCOps::notaryIdentities) invokeRpc(CordaRPCOps::notaryIdentities)
) )
driver(DriverParameters(extraCordappPackagesToScan = listOf("net.corda.finance"), isDebug = true)) { driver(DriverParameters(extraCordappPackagesToScan = listOf("net.corda.finance"))) {
val bocManager = User("bocManager", "password1", permissions = setOf( val bocManager = User("bocManager", "password1", permissions = setOf(
startFlow<CashIssueAndPaymentFlow>()) + commonPermissions) startFlow<CashIssueAndPaymentFlow>()) + commonPermissions)
val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet<String>() + commonPermissions) val bigCorpCFO = User("bigCorpCFO", "password2", permissions = emptySet<String>() + commonPermissions)

View File

@ -22,7 +22,7 @@ import net.corda.testing.driver.driver
* Do not use in a production environment. * Do not use in a production environment.
*/ */
fun main(args: Array<String>) { fun main(args: Array<String>) {
driver(DriverParameters(useTestClock = true, isDebug = true, waitForAllNodesToFinish = true)) { driver(DriverParameters(useTestClock = true, waitForAllNodesToFinish = true)) {
val (nodeA, nodeB) = listOf( val (nodeA, nodeB) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME), startNode(providedName = DUMMY_BANK_A_NAME),
startNode(providedName = DUMMY_BANK_B_NAME), startNode(providedName = DUMMY_BANK_B_NAME),

View File

@ -72,7 +72,6 @@ class IRSDemoTest : IntegrationTest() {
springDriver(DriverParameters( springDriver(DriverParameters(
useTestClock = true, useTestClock = true,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, rpcUsers = rpcUsers)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, rpcUsers = rpcUsers)),
isDebug = true,
extraCordappPackagesToScan = listOf("net.corda.irs") extraCordappPackagesToScan = listOf("net.corda.irs")
)) { )) {
val (controller, nodeA, nodeB) = listOf( val (controller, nodeA, nodeB) = listOf(

View File

@ -69,7 +69,6 @@ class SimmValuationTest : IntegrationTest() {
val logConfigFile = projectRootDir / "samples" / "simm-valuation-demo" / "src" / "main" / "resources" / "log4j2.xml" val logConfigFile = projectRootDir / "samples" / "simm-valuation-demo" / "src" / "main" / "resources" / "log4j2.xml"
assertThat(logConfigFile).isRegularFile() assertThat(logConfigFile).isRegularFile()
driver(DriverParameters( driver(DriverParameters(
isDebug = true,
extraCordappPackagesToScan = listOf("net.corda.vega.contracts", "net.corda.vega.plugin.customserializers"), extraCordappPackagesToScan = listOf("net.corda.vega.contracts", "net.corda.vega.plugin.customserializers"),
systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString())) systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString()))
) { ) {

View File

@ -23,7 +23,7 @@ import net.corda.testing.driver.driver
* via the web api. * via the web api.
*/ */
fun main(args: Array<String>) { fun main(args: Array<String>) {
driver(DriverParameters(isDebug = true, waitForAllNodesToFinish = true)) { driver(DriverParameters(waitForAllNodesToFinish = true)) {
val (nodeA, nodeB, nodeC) = listOf( val (nodeA, nodeB, nodeC) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME), startNode(providedName = DUMMY_BANK_A_NAME),
startNode(providedName = DUMMY_BANK_B_NAME), startNode(providedName = DUMMY_BANK_B_NAME),

View File

@ -96,7 +96,7 @@ class TraderDemoTest : IntegrationTest() {
@Test @Test
fun `Tudor test`() { fun `Tudor test`() {
driver(DriverParameters(isDebug = true, startNodesInProcess = false, inMemoryDB = false, extraCordappPackagesToScan = listOf("net.corda.finance"))) { driver(DriverParameters(startNodesInProcess = false, inMemoryDB = false, extraCordappPackagesToScan = listOf("net.corda.finance"))) {
val demoUser = User("demo", "demo", setOf(startFlow<SellerFlow>(), all())) val demoUser = User("demo", "demo", setOf(startFlow<SellerFlow>(), all()))
val bankUser = User("user1", "test", permissions = setOf(all())) val bankUser = User("user1", "test", permissions = setOf(all()))
val (nodeA, nodeB, bankNode) = listOf( val (nodeA, nodeB, bankNode) = listOf(

View File

@ -33,7 +33,7 @@ fun main(args: Array<String>) {
startFlow<SellerFlow>(), startFlow<SellerFlow>(),
all()) all())
val demoUser = listOf(User("demo", "demo", permissions)) val demoUser = listOf(User("demo", "demo", permissions))
driver(DriverParameters(driverDirectory = "build" / "trader-demo-nodes", isDebug = true, waitForAllNodesToFinish = true)) { driver(DriverParameters(driverDirectory = "build" / "trader-demo-nodes", waitForAllNodesToFinish = true)) {
val user = User("user1", "test", permissions = setOf(startFlow<CashIssueFlow>(), val user = User("user1", "test", permissions = setOf(startFlow<CashIssueFlow>(),
startFlow<CommercialPaperIssueFlow>(), startFlow<CommercialPaperIssueFlow>(),
startFlow<SellerFlow>())) startFlow<SellerFlow>()))

View File

@ -67,7 +67,6 @@ class CordformNodeRunner(val cordformDefinition: CordformDefinition) {
.mapNotNull { address -> address?.let { NetworkHostAndPort.parse(it).port } } .mapNotNull { address -> address?.let { NetworkHostAndPort.parse(it).port } }
.max()!! .max()!!
internalDriver( internalDriver(
isDebug = true,
jmxPolicy = JmxPolicy(true), jmxPolicy = JmxPolicy(true),
driverDirectory = cordformDefinition.nodesDirectory, driverDirectory = cordformDefinition.nodesDirectory,
extraCordappPackagesToScan = extraPackagesToScan, extraCordappPackagesToScan = extraPackagesToScan,

View File

@ -67,7 +67,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
@Test @Test
fun `shell should not log in with invalid credentials`() { fun `shell should not log in with invalid credentials`() {
val user = User("u", "p", setOf()) val user = User("u", "p", setOf())
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
val nodeFuture = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user), startInSameProcess = true) val nodeFuture = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user), startInSameProcess = true)
val node = nodeFuture.getOrThrow() val node = nodeFuture.getOrThrow()
@ -108,7 +108,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert) val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert)
val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password") val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password")
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow().use { node -> startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(), val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
@ -136,7 +136,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert1) val trustStorePath = saveToTrustStore(tempFolder.root.toPath() / "truststore.jks", cert1)
val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password") val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password")
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow().use { node -> startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(), val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
@ -153,7 +153,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
@Test @Test
fun `internal shell user should not be able to connect if node started with devMode=false`() { fun `internal shell user should not be able to connect if node started with devMode=false`() {
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
startNode().getOrThrow().use { node -> startNode().getOrThrow().use { node ->
val conf = (node as NodeHandleInternal).configuration.toShellConfig() val conf = (node as NodeHandleInternal).configuration.toShellConfig()
InteractiveShell.startShellInternal(conf) InteractiveShell.startShellInternal(conf)
@ -219,7 +219,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password") val clientSslOptions = ClientRpcSslOptions(trustStorePath, "password")
var successful = false var successful = false
driver(DriverParameters(isDebug = true, startNodesInProcess = true, portAllocation = RandomFree)) { driver(DriverParameters(startNodesInProcess = true, portAllocation = RandomFree)) {
startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow().use { node -> startNode(rpcUsers = listOf(user), customOverrides = brokerSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(), val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),

View File

@ -117,7 +117,7 @@ class SSHServerTest : IntegrationTest() {
val user = User("u", "p", setOf(startFlow<FlowICanRun>(), val user = User("u", "p", setOf(startFlow<FlowICanRun>(),
invokeRpc(CordaRPCOps::wellKnownPartyFromX500Name))) invokeRpc(CordaRPCOps::wellKnownPartyFromX500Name)))
// The driver will automatically pick up the annotated flows below // The driver will automatically pick up the annotated flows below
driver(DriverParameters(isDebug = true)) { driver {
val node = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user), val node = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user),
customOverrides = mapOf("sshd" to mapOf("port" to 2222))) customOverrides = mapOf("sshd" to mapOf("port" to 2222)))
node.getOrThrow() node.getOrThrow()
@ -146,7 +146,7 @@ class SSHServerTest : IntegrationTest() {
fun `ssh runs flows`() { fun `ssh runs flows`() {
val user = User("u", "p", setOf(startFlow<FlowICanRun>())) val user = User("u", "p", setOf(startFlow<FlowICanRun>()))
// The driver will automatically pick up the annotated flows below // The driver will automatically pick up the annotated flows below
driver(DriverParameters(isDebug = true)) { driver {
val node = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user), val node = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user),
customOverrides = mapOf("sshd" to mapOf("port" to 2222))) customOverrides = mapOf("sshd" to mapOf("port" to 2222)))
node.getOrThrow() node.getOrThrow()