Merge remote-tracking branch 'open/master' into shams-os-merge-191217

# Conflicts:
#	core/src/main/kotlin/net/corda/core/node/services/NotaryService.kt
#	node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt
#	node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt
#	node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt
#	node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
This commit is contained in:
Shams Asari 2017-12-19 23:44:07 +00:00
commit de9565b96a
32 changed files with 261 additions and 252 deletions

View File

@ -1862,7 +1862,7 @@ public @interface net.corda.core.node.services.CordaService
@org.jetbrains.annotations.NotNull public static final String ID_PREFIX = "corda.notary."
##
public static final class net.corda.core.node.services.NotaryService$Companion extends java.lang.Object
@org.jetbrains.annotations.NotNull public final String constructId(boolean, boolean, boolean, boolean)
@kotlin.Deprecated @org.jetbrains.annotations.NotNull public final String constructId(boolean, boolean, boolean, boolean)
##
public abstract class net.corda.core.node.services.PartyInfo extends java.lang.Object
@org.jetbrains.annotations.NotNull public abstract net.corda.core.identity.Party getParty()

View File

@ -2,7 +2,7 @@ package net.corda.core.identity
import com.google.common.collect.ImmutableSet
import net.corda.core.internal.LegalNameValidator
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.unspecifiedCountry
import net.corda.core.internal.x500Name
import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.asn1.ASN1Encodable
@ -36,7 +36,9 @@ data class CordaX500Name(val commonName: String?,
val locality: String,
val state: String?,
val country: String) {
constructor(commonName: String, organisation: String, locality: String, country: String) : this(commonName = commonName, organisationUnit = null, organisation = organisation, locality = locality, state = null, country = country)
constructor(commonName: String, organisation: String, locality: String, country: String) :
this(commonName = commonName, organisationUnit = null, organisation = organisation, locality = locality, state = null, country = country)
/**
* @param organisation name of the organisation.
* @param locality locality of the organisation, typically nearest major city.
@ -79,8 +81,6 @@ data class CordaX500Name(val commonName: String?,
const val MAX_LENGTH_ORGANISATION_UNIT = 64
const val MAX_LENGTH_COMMON_NAME = 64
private val supportedAttributes = setOf(BCStyle.O, BCStyle.C, BCStyle.L, BCStyle.CN, BCStyle.ST, BCStyle.OU)
@VisibleForTesting
val unspecifiedCountry = "ZZ"
private val countryCodes: Set<String> = ImmutableSet.copyOf(Locale.getISOCountries() + unspecifiedCountry)
@JvmStatic
fun build(principal: X500Principal): CordaX500Name {

View File

@ -5,6 +5,7 @@ package net.corda.core.internal
import net.corda.core.cordapp.CordappProvider
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256
import net.corda.core.identity.CordaX500Name
import net.corda.core.node.ServicesForResolution
import net.corda.core.serialization.SerializationContext
import net.corda.core.transactions.TransactionBuilder
@ -118,6 +119,8 @@ fun Path.isDirectory(vararg options: LinkOption): Boolean = Files.isDirectory(th
inline val Path.size: Long get() = Files.size(this)
inline fun <R> Path.list(block: (Stream<Path>) -> R): R = Files.list(this).use(block)
fun Path.deleteIfExists(): Boolean = Files.deleteIfExists(this)
fun Path.reader(charset: Charset = UTF_8): BufferedReader = Files.newBufferedReader(this, charset)
fun Path.writer(charset: Charset = UTF_8, vararg options: OpenOption): BufferedWriter = Files.newBufferedWriter(this, charset, *options)
fun Path.readAll(): ByteArray = Files.readAllBytes(this)
inline fun <R> Path.read(vararg options: OpenOption, block: (InputStream) -> R): R = Files.newInputStream(this, *options).use(block)
inline fun Path.write(createDirs: Boolean = false, vararg options: OpenOption = emptyArray(), block: (OutputStream) -> Unit) {
@ -316,3 +319,8 @@ fun ExecutorService.join() {
// Try forever. Do not give up, tests use this method to assert the executor has no more tasks.
}
}
@Suppress("unused")
@VisibleForTesting
val CordaX500Name.Companion.unspecifiedCountry
get() = "ZZ"

View File

@ -15,16 +15,11 @@ import java.security.PublicKey
abstract class NotaryService : SingletonSerializeAsToken() {
companion object {
@Deprecated("No longer used")
const val ID_PREFIX = "corda.notary."
@JvmOverloads
fun constructId(
validating: Boolean,
raft: Boolean = false,
bft: Boolean = false,
custom: Boolean = false,
mysql: Boolean = false
): String {
require(Booleans.countTrue(raft, bft, custom, mysql) <= 1) { "At most one of raft, bft, mysql or custom may be true" }
@Deprecated("No longer used")
fun constructId(validating: Boolean, raft: Boolean = false, bft: Boolean = false, custom: Boolean = false): String {
require(Booleans.countTrue(raft, bft, custom) <= 1) { "At most one of raft, bft or custom may be true" }
return StringBuffer(ID_PREFIX).apply {
append(if (validating) "validating" else "simple")
if (raft) append(".raft")

View File

@ -9,8 +9,8 @@ import net.corda.core.serialization.serialize
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.toBase58String
import net.corda.nodeapi.internal.crypto.*
import net.corda.testing.internal.kryoSpecific
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.internal.kryoSpecific
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
@ -24,6 +24,7 @@ class CompositeKeyTests {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
@Rule
@JvmField
val tempFolder: TemporaryFolder = TemporaryFolder()
@ -40,9 +41,9 @@ class CompositeKeyTests {
private val secureHash = message.sha256()
// By lazy is required so that the serialisers are configured before vals initialisation takes place (they internally invoke serialise).
val aliceSignature by lazy { aliceKey.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(alicePublicKey).schemeNumberID))) }
val bobSignature by lazy { bobKey.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(bobPublicKey).schemeNumberID))) }
val charlieSignature by lazy { charlieKey.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(charliePublicKey).schemeNumberID))) }
private val aliceSignature by lazy { aliceKey.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(alicePublicKey).schemeNumberID))) }
private val bobSignature by lazy { bobKey.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(bobPublicKey).schemeNumberID))) }
private val charlieSignature by lazy { charlieKey.sign(SignableData(secureHash, SignatureMetadata(1, Crypto.findSignatureScheme(charliePublicKey).schemeNumberID))) }
@Test
fun `(Alice) fulfilled by Alice signature`() {
@ -337,7 +338,7 @@ class CompositeKeyTests {
val ca = X509Utilities.createSelfSignedCACertificate(caName, caKeyPair)
// Sign the composite key with the self sign CA.
val compositeKeyCert = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, ca, caKeyPair, caName.copy(commonName = "CompositeKey"), compositeKey)
val compositeKeyCert = X509Utilities.createCertificate(CertificateType.LEGAL_IDENTITY, ca, caKeyPair, caName, compositeKey)
// Store certificate to keystore.
val keystorePath = tempFolder.root.toPath() / "keystore.jks"

View File

@ -159,7 +159,7 @@ class AttachmentSerializationTest {
private fun rebootClientAndGetAttachmentContent(checkAttachmentsOnLoad: Boolean = true): String {
client.dispose()
client = mockNet.createNode(MockNodeParameters(client.internals.id), { args ->
client = mockNet.createNode(MockNodeParameters(client.internals.id, client.internals.configuration.myLegalName), { args ->
object : MockNetwork.MockNode(args) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = checkAttachmentsOnLoad }
}

View File

@ -92,7 +92,6 @@ nodes. Here is an example ``Cordform`` task called ``deployNodes`` that creates
}
node {
name "O=PartyA,L=London,C=GB"
advertisedServices = []
p2pPort 10005
rpcPort 10006
webPort 10007
@ -103,7 +102,6 @@ nodes. Here is an example ``Cordform`` task called ``deployNodes`` that creates
}
node {
name "O=PartyB,L=New York,C=US"
advertisedServices = []
p2pPort 10009
rpcPort 10010
webPort 10011

View File

@ -22,7 +22,7 @@ service.
directory "./build/nodes"
node {
name "O=Controller,L=London,C=GB"
advertisedServices = ["corda.notary.validating"]
notary = [validating : true]
p2pPort 10002
rpcPort 10003
cordapps = ["net.corda:corda-finance:$corda_release_version"]

View File

@ -13,42 +13,54 @@ import org.slf4j.LoggerFactory
import java.nio.file.Path
import java.security.cert.X509Certificate
object ServiceIdentityGenerator {
object IdentityGenerator {
private val log = LoggerFactory.getLogger(javaClass)
const val NODE_IDENTITY_ALIAS_PREFIX = "identity"
const val DISTRIBUTED_NOTARY_ALIAS_PREFIX = "distributed-notary"
fun generateNodeIdentity(dir: Path, legalName: CordaX500Name, customRootCert: X509Certificate? = null): Party {
return generateToDisk(listOf(dir), legalName, NODE_IDENTITY_ALIAS_PREFIX, threshold = 1, customRootCert = customRootCert)
}
fun generateDistributedNotaryIdentity(dirs: List<Path>, notaryName: CordaX500Name, threshold: Int = 1, customRootCert: X509Certificate? = null): Party {
return generateToDisk(dirs, notaryName, DISTRIBUTED_NOTARY_ALIAS_PREFIX, threshold, customRootCert)
}
/**
* Generates signing key pairs and a common distributed service identity for a set of nodes.
* The key pairs and the group identity get serialized to disk in the corresponding node directories.
* This method should be called *before* any of the nodes are started.
*
* @param dirs List of node directories to place the generated identity and key pairs in.
* @param serviceName The legal name of the distributed service.
* @param name The name of the identity.
* @param threshold The threshold for the generated group [CompositeKey].
* @param customRootCert the certificate to use a Corda root CA. If not specified the one in
* certificates/cordadevcakeys.jks is used.
* @param customRootCert the certificate to use as the Corda root CA. If not specified the one in
* internal/certificates/cordadevcakeys.jks is used.
*/
fun generateToDisk(dirs: List<Path>,
serviceName: CordaX500Name,
serviceId: String,
threshold: Int = 1,
customRootCert: X509Certificate? = null): Party {
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
private fun generateToDisk(dirs: List<Path>,
name: CordaX500Name,
aliasPrefix: String,
threshold: Int,
customRootCert: X509Certificate?): Party {
log.trace { "Generating identity \"$name\" for nodes: ${dirs.joinToString()}" }
val keyPairs = (1..dirs.size).map { generateKeyPair() }
val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold)
val key = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold)
val caKeyStore = loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/cordadevcakeys.jks"), "cordacadevpass")
val intermediateCa = caKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, "cordacadevkeypass")
val rootCert = customRootCert ?: caKeyStore.getCertificate(X509Utilities.CORDA_ROOT_CA)
keyPairs.zip(dirs) { keyPair, dir ->
val serviceKeyCert = X509Utilities.createCertificate(CertificateType.SERVICE_IDENTITY, intermediateCa.certificate, intermediateCa.keyPair, serviceName, keyPair.public)
val compositeKeyCert = X509Utilities.createCertificate(CertificateType.SERVICE_IDENTITY, intermediateCa.certificate, intermediateCa.keyPair, serviceName, notaryKey)
val serviceKeyCert = X509Utilities.createCertificate(CertificateType.SERVICE_IDENTITY, intermediateCa.certificate, intermediateCa.keyPair, name, keyPair.public)
val compositeKeyCert = X509Utilities.createCertificate(CertificateType.SERVICE_IDENTITY, intermediateCa.certificate, intermediateCa.keyPair, name, key)
val certPath = (dir / "certificates").createDirectories() / "distributedService.jks"
val keystore = loadOrCreateKeyStore(certPath, "cordacadevpass")
keystore.setCertificateEntry("$serviceId-composite-key", compositeKeyCert.cert)
keystore.setKeyEntry("$serviceId-private-key", keyPair.private, "cordacadevkeypass".toCharArray(), arrayOf(serviceKeyCert.cert, intermediateCa.certificate.cert, rootCert))
keystore.setCertificateEntry("$aliasPrefix-composite-key", compositeKeyCert.cert)
keystore.setKeyEntry("$aliasPrefix-private-key", keyPair.private, "cordacadevkeypass".toCharArray(), arrayOf(serviceKeyCert.cert, intermediateCa.certificate.cert, rootCert))
keystore.save(certPath, "cordacadevpass")
}
return Party(serviceName, notaryKey)
return Party(name, key)
}
}

View File

@ -7,7 +7,8 @@ import net.corda.core.crypto.random63BitValue
import net.corda.core.internal.CertRole
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.cert
import net.corda.core.internal.read
import net.corda.core.internal.reader
import net.corda.core.internal.writer
import net.corda.core.internal.x500Name
import net.corda.core.utilities.days
import net.corda.core.utilities.millis
@ -48,8 +49,6 @@ object X509Utilities {
const val CORDA_CLIENT_TLS = "cordaclienttls"
const val CORDA_CLIENT_CA = "cordaclientca"
const val CORDA_CLIENT_CA_CN = "Corda Client CA Certificate"
private val DEFAULT_VALIDITY_WINDOW = Pair(0.millis, 3650.days)
/**
@ -162,7 +161,7 @@ object X509Utilities {
*/
@JvmStatic
fun saveCertificateAsPEMFile(x509Certificate: X509Certificate, file: Path) {
JcaPEMWriter(file.toFile().writer()).use {
JcaPEMWriter(file.writer()).use {
it.writeObject(x509Certificate)
}
}
@ -174,9 +173,8 @@ object X509Utilities {
*/
@JvmStatic
fun loadCertificateFromPEMFile(file: Path): X509Certificate {
return file.read {
val reader = PemReader(it.reader())
val pemObject = reader.readPemObject()
return file.reader().use {
val pemObject = PemReader(it).readPemObject()
val certHolder = X509CertificateHolder(pemObject.content)
certHolder.isValidOn(Date())
certHolder.cert

View File

@ -13,7 +13,6 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.deleteIfExists
import net.corda.core.internal.div
import net.corda.core.node.services.NotaryService
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.NetworkHostAndPort
@ -26,6 +25,8 @@ import net.corda.node.services.transactions.minClusterSize
import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.IdentityGenerator
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NotaryInfo
import net.corda.testing.IntegrationTest
import net.corda.testing.IntegrationTestSchemas
@ -68,10 +69,9 @@ class BFTNotaryServiceTests : IntegrationTest() {
(Paths.get("config") / "currentView").deleteIfExists() // XXX: Make config object warn if this exists?
val replicaIds = (0 until clusterSize)
notary = ServiceIdentityGenerator.generateToDisk(
notary = IdentityGenerator.generateDistributedNotaryIdentity(
replicaIds.map { mockNet.baseDirectory(mockNet.nextNodeId + it) },
CordaX500Name("BFT", "Zurich", "CH"),
NotaryService.constructId(validating = false, bft = true))
CordaX500Name("BFT", "Zurich", "CH"))
val networkParameters = NetworkParametersCopier(testNetworkParameters(listOf(NotaryInfo(notary, false))))

View File

@ -11,15 +11,17 @@ import net.corda.core.internal.concurrent.map
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.testing.*
import net.corda.testing.DUMMY_BANK_A_NAME
import net.corda.testing.chooseIdentity
import net.corda.testing.contracts.DummyContract
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
import net.corda.testing.dummyCommand
import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.startFlow
import org.junit.ClassRule
import net.corda.testing.node.startFlow
import org.junit.Test
import java.util.*
import kotlin.test.assertEquals
@ -31,15 +33,15 @@ class RaftNotaryServiceTests : IntegrationTest() {
val databaseSchemas = IntegrationTestSchemas( "RAFTNotaryService_0", "RAFTNotaryService_1", "RAFTNotaryService_2",
DUMMY_BANK_A_NAME.toDatabaseSchemaName())
}
private val notaryName = CordaX500Name(RaftValidatingNotaryService.id, "RAFT Notary Service", "London", "GB")
private val notaryName = CordaX500Name("RAFT Notary Service", "London", "GB")
@Test
fun `detect double spend`() {
driver(
startNodesInProcess = true,
extraCordappPackagesToScan = listOf("net.corda.testing.contracts"),
notarySpecs = listOf(NotarySpec(notaryName, cluster = ClusterSpec.Raft(clusterSize = 3))))
{
notarySpecs = listOf(NotarySpec(notaryName, cluster = ClusterSpec.Raft(clusterSize = 3)))
) {
val bankA = startNode(providedName = DUMMY_BANK_A_NAME).map { (it as NodeHandle.InProcess).node }.getOrThrow()
val inputState = issueState(bankA, defaultNotaryIdentity)

View File

@ -19,6 +19,9 @@ import net.corda.node.services.messaging.ReceivedMessage
import net.corda.node.services.messaging.send
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.testing.*
import net.corda.node.services.messaging.*
import net.corda.testing.ALICE_NAME
import net.corda.testing.chooseIdentity
import net.corda.testing.driver.DriverDSL
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
@ -38,7 +41,7 @@ class P2PMessagingTest : IntegrationTest() {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName(), "DistributedService_0", "DistributedService_1")
val DISTRIBUTED_SERVICE_NAME = CordaX500Name(RaftValidatingNotaryService.id, "DistributedService", "London", "GB")
val DISTRIBUTED_SERVICE_NAME = CordaX500Name("DistributedService", "London", "GB")
}
@Test

View File

@ -60,8 +60,12 @@ import net.corda.node.services.vault.NodeVaultService
import net.corda.node.services.vault.VaultSoftLockManager
import net.corda.node.shell.InteractiveShell
import net.corda.node.utilities.AffinityExecutor
import net.corda.nodeapi.internal.IdentityGenerator
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.crypto.*
import net.corda.nodeapi.internal.crypto.KeyStoreWrapper
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.loadKeyStore
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.nodeapi.internal.persistence.CordaPersistence
@ -137,25 +141,19 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
protected val services: ServiceHubInternal get() = _services
private lateinit var _services: ServiceHubInternalImpl
protected var myNotaryIdentity: PartyAndCertificate? = null
protected lateinit var checkpointStorage: CheckpointStorage
private lateinit var checkpointStorage: CheckpointStorage
private lateinit var tokenizableServices: List<Any>
protected lateinit var attachments: NodeAttachmentService
protected lateinit var network: MessagingService
protected val runOnStop = ArrayList<() -> Any?>()
protected val _nodeReadyFuture = openFuture<Unit>()
private val _nodeReadyFuture = openFuture<Unit>()
protected var networkMapClient: NetworkMapClient? = null
lateinit var securityManager: RPCSecurityManager get
/** Completes once the node has successfully registered with the network map service
* or has loaded network map data from local database */
val nodeReadyFuture: CordaFuture<Unit>
get() = _nodeReadyFuture
/** A [CordaX500Name] with null common name. */
protected val myLegalName: CordaX500Name by lazy {
val cert = loadKeyStore(configuration.nodeKeystore, configuration.keyStorePassword).getX509Certificate(X509Utilities.CORDA_CLIENT_CA)
CordaX500Name.build(cert.subjectX500Principal).copy(commonName = null)
}
val nodeReadyFuture: CordaFuture<Unit> get() = _nodeReadyFuture
open val serializationWhitelists: List<SerializationWhitelist> by lazy {
cordappLoader.cordapps.flatMap { it.serializationWhitelists }
@ -330,7 +328,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
)
// Check if we have already stored a version of 'our own' NodeInfo, this is to avoid regenerating it with
// a different timestamp.
networkMapCache.getNodesByLegalName(myLegalName).firstOrNull()?.let {
networkMapCache.getNodesByLegalName(configuration.myLegalName).firstOrNull()?.let {
if (info.copy(serial = it.serial) == it) {
info = it
}
@ -756,13 +754,10 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
val (id, singleName) = if (notaryConfig == null || !notaryConfig.isClusterConfig) {
// Node's main identity or if it's a single node notary
Pair("identity", myLegalName)
Pair(IdentityGenerator.NODE_IDENTITY_ALIAS_PREFIX, configuration.myLegalName)
} else {
val notaryId = notaryConfig.run {
NotaryService.constructId(validating, raft != null, bftSMaRt != null, custom, mysql != null)
}
// The node is part of a distributed notary whose identity must already be generated beforehand.
Pair(notaryId, null)
Pair(IdentityGenerator.DISTRIBUTED_NOTARY_ALIAS_PREFIX, null)
}
// TODO: Integrate with Key management service?
val privateKeyAlias = "$id-private-key"
@ -770,7 +765,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
if (!keyStore.containsAlias(privateKeyAlias)) {
singleName ?: throw IllegalArgumentException(
"Unable to find in the key store the identity of the distributed notary ($id) the node is part of")
// TODO: Remove use of [ServiceIdentityGenerator.generateToDisk].
// TODO: Remove use of [IdentityGenerator.generateToDisk].
log.info("$privateKeyAlias not found in key store ${configuration.nodeKeystore}, generating fresh key!")
keyStore.signAndSaveNewKeyPair(singleName, privateKeyAlias, generateKeyPair())
}

View File

@ -69,7 +69,7 @@ fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500Name) {
val caKeyStore = loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/cordadevcakeys.jks"), "cordacadevpass")
createKeystoreForCordaNode(sslKeystore, nodeKeystore, keyStorePassword, keyStorePassword, caKeyStore, "cordacadevkeypass", myLegalName)
// Move distributed service composite key (generated by ServiceIdentityGenerator.generateToDisk) to keystore if exists.
// Move distributed service composite key (generated by IdentityGenerator.generateToDisk) to keystore if exists.
val distributedServiceKeystore = certificatesDirectory / "distributedService.jks"
if (distributedServiceKeystore.exists()) {
val serviceKeystore = loadKeyStore(distributedServiceKeystore, "cordacadevpass")
@ -111,18 +111,17 @@ fun createKeystoreForCordaNode(sslKeyStorePath: Path,
val (intermediateCACert, intermediateCAKeyPair) = caKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, caKeyPassword)
val clientKey = Crypto.generateKeyPair(signatureScheme)
val clientName = legalName.copy(commonName = null)
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, clientName.x500Name))), arrayOf())
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.x500Name))), arrayOf())
val clientCACert = X509Utilities.createCertificate(CertificateType.NODE_CA,
intermediateCACert,
intermediateCAKeyPair,
clientName.copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN),
legalName,
clientKey.public,
nameConstraints = nameConstraints)
val tlsKey = Crypto.generateKeyPair(signatureScheme)
val clientTLSCert = X509Utilities.createCertificate(CertificateType.TLS, clientCACert, clientKey, clientName, tlsKey.public)
val clientTLSCert = X509Utilities.createCertificate(CertificateType.TLS, clientCACert, clientKey, legalName, tlsKey.public)
val keyPass = keyPassword.toCharArray()

View File

@ -24,6 +24,7 @@ import javax.annotation.concurrent.ThreadSafe
*
* @param identities initial set of identities for the service, typically only used for unit tests.
*/
// TODO There is duplicated logic between this and PersistentIdentityService
@ThreadSafe
class InMemoryIdentityService(identities: Array<out PartyAndCertificate>,
trustRoot: X509CertificateHolder) : SingletonSerializeAsToken(), IdentityServiceInternal {

View File

@ -26,6 +26,7 @@ import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Lob
// TODO There is duplicated logic between this and InMemoryIdentityService
@ThreadSafe
class PersistentIdentityService(override val trustRoot: X509Certificate,
vararg caCertificates: X509Certificate) : SingletonSerializeAsToken(), IdentityServiceInternal {

View File

@ -34,12 +34,13 @@ import kotlin.concurrent.thread
*
* A transaction is notarised when the consensus is reached by the cluster on its uniqueness, and time-window validity.
*/
class BFTNonValidatingNotaryService(override val services: ServiceHubInternal,
override val notaryIdentityKey: PublicKey,
private val bftSMaRtConfig: BFTSMaRtConfiguration,
cluster: BFTSMaRt.Cluster) : NotaryService() {
class BFTNonValidatingNotaryService(
override val services: ServiceHubInternal,
override val notaryIdentityKey: PublicKey,
private val bftSMaRtConfig: BFTSMaRtConfiguration,
cluster: BFTSMaRt.Cluster
) : NotaryService() {
companion object {
val id = constructId(validating = false, bft = true)
private val log = contextLogger()
}

View File

@ -8,14 +8,13 @@ import net.corda.core.node.services.TrustedAuthorityNotaryService
import java.security.PublicKey
/** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
class RaftNonValidatingNotaryService(override val services: ServiceHub,
override val notaryIdentityKey: PublicKey,
override val uniquenessProvider: RaftUniquenessProvider) : TrustedAuthorityNotaryService() {
companion object {
val id = constructId(validating = false, raft = true)
}
class RaftNonValidatingNotaryService(
override val services: ServiceHub,
override val notaryIdentityKey: PublicKey,
override val uniquenessProvider: RaftUniquenessProvider
) : TrustedAuthorityNotaryService() {
override val timeWindowChecker: TimeWindowChecker = TimeWindowChecker(services.clock)
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service {
return NonValidatingNotaryFlow(otherPartySession, this)
}

View File

@ -8,14 +8,13 @@ import net.corda.core.node.services.TrustedAuthorityNotaryService
import java.security.PublicKey
/** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
class RaftValidatingNotaryService(override val services: ServiceHub,
override val notaryIdentityKey: PublicKey,
override val uniquenessProvider: RaftUniquenessProvider) : TrustedAuthorityNotaryService() {
companion object {
val id = constructId(validating = true, raft = true)
}
class RaftValidatingNotaryService(
override val services: ServiceHub,
override val notaryIdentityKey: PublicKey,
override val uniquenessProvider: RaftUniquenessProvider
) : TrustedAuthorityNotaryService() {
override val timeWindowChecker: TimeWindowChecker = TimeWindowChecker(services.clock)
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service {
return ValidatingNotaryFlow(otherPartySession, this)
}

View File

@ -9,10 +9,8 @@ import java.security.PublicKey
/** A Notary service that validates the transaction chain of the submitted transaction before committing it */
class ValidatingNotaryService(override val services: ServiceHubInternal, override val notaryIdentityKey: PublicKey) : TrustedAuthorityNotaryService() {
companion object {
val id = constructId(validating = true)
}
override val timeWindowChecker = TimeWindowChecker(services.clock)
override val uniquenessProvider = PersistentUniquenessProvider()
override fun createServiceFlow(otherPartySession: FlowSession): NotaryFlow.Service = ValidatingNotaryFlow(otherPartySession, this)

View File

@ -103,10 +103,9 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v
println("Generating SSL certificate for node messaging service.")
val sslKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val caCert = caKeyStore.getX509Certificate(CORDA_CLIENT_CA).toX509CertHolder()
val sslCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, keyPair, CordaX500Name.build(caCert.cert.subjectX500Principal).copy(commonName = null), sslKey.public)
val sslCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, keyPair, CordaX500Name.build(caCert.cert.subjectX500Principal), sslKey.public)
val sslKeyStore = loadOrCreateKeyStore(config.sslKeystore, keystorePassword)
sslKeyStore.addOrReplaceKey(CORDA_CLIENT_TLS, sslKey.private, privateKeyPassword.toCharArray(),
arrayOf(sslCert.cert, *certificates))
sslKeyStore.addOrReplaceKey(CORDA_CLIENT_TLS, sslKey.private, privateKeyPassword.toCharArray(), arrayOf(sslCert.cert, *certificates))
sslKeyStore.save(config.sslKeystore, config.keyStorePassword)
println("SSL private key and certificate stored in ${config.sslKeystore}.")
// All done, clean up temp files.

View File

@ -656,7 +656,7 @@ class FlowFrameworkTests {
private inline fun <reified P : FlowLogic<*>> StartedNode<MockNode>.restartAndGetRestoredFlow() = internals.run {
disableDBCloseOnStop() // Handover DB to new node copy
stop()
val newNode = mockNet.createNode(MockNodeParameters(id))
val newNode = mockNet.createNode(MockNodeParameters(id, configuration.myLegalName))
newNode.internals.acceptableLiveFiberCountOnStop = 1
manuallyCloseDB()
mockNet.runNetwork()

View File

@ -1,5 +1,7 @@
package net.corda.node.utilities.registration
import com.google.common.jimfs.Configuration.unix
import com.google.common.jimfs.Jimfs
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.eq
@ -7,68 +9,61 @@ import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.*
import net.corda.core.internal.cert
import net.corda.core.internal.createDirectories
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.crypto.*
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.getX509Certificate
import net.corda.nodeapi.internal.crypto.loadKeyStore
import net.corda.testing.ALICE_NAME
import net.corda.testing.internal.rigorousMock
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.security.cert.Certificate
import kotlin.test.assertEquals
import java.security.cert.X509Certificate
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class NetworkRegistrationHelperTest {
@Rule
@JvmField
val tempFolder = TemporaryFolder()
private val fs = Jimfs.newFileSystem(unix())
private val requestId = SecureHash.randomSHA256().toString()
private val nodeLegalName = ALICE_NAME
private val intermediateCaName = CordaX500Name("CORDA_INTERMEDIATE_CA", "R3 Ltd", "London", "GB")
private val rootCaName = CordaX500Name("CORDA_ROOT_CA", "R3 Ltd", "London", "GB")
private val nodeCaCert = createCaCert(nodeLegalName)
private val intermediateCaCert = createCaCert(intermediateCaName)
private val rootCaCert = createCaCert(rootCaName)
private lateinit var config: NodeConfiguration
private val identities = listOf("CORDA_CLIENT_CA",
"CORDA_INTERMEDIATE_CA",
"CORDA_ROOT_CA")
.map { CordaX500Name(commonName = it, organisation = "R3 Ltd", locality = "London", country = "GB") }
private val certs = identities.map { X509Utilities.createSelfSignedCACertificate(it, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) }
.map { it.cert }.toTypedArray()
private val certService = mockRegistrationResponse(*certs)
@Before
fun init() {
val baseDirectory = fs.getPath("/baseDir").createDirectories()
abstract class AbstractNodeConfiguration : NodeConfiguration
config = rigorousMock<AbstractNodeConfiguration>().also {
doReturn(tempFolder.root.toPath()).whenever(it).baseDirectory
doReturn(baseDirectory).whenever(it).baseDirectory
doReturn("trustpass").whenever(it).trustStorePassword
doReturn("cordacadevpass").whenever(it).keyStorePassword
doReturn(ALICE_NAME).whenever(it).myLegalName
doReturn(nodeLegalName).whenever(it).myLegalName
doReturn("").whenever(it).emailAddress
}
}
@After
fun cleanUp() {
fs.close()
}
@Test
fun `successful registration`() {
assertFalse(config.nodeKeystore.exists())
assertFalse(config.sslKeystore.exists())
config.trustStoreFile.parent.createDirectories()
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, certs.last())
it.save(config.trustStoreFile, config.trustStorePassword)
}
assertThat(config.nodeKeystore).doesNotExist()
assertThat(config.sslKeystore).doesNotExist()
assertThat(config.trustStoreFile).doesNotExist()
NetworkRegistrationHelper(config, certService).buildKeystore()
saveTrustStoreWithRootCa(rootCaCert)
assertTrue(config.nodeKeystore.exists())
assertTrue(config.sslKeystore.exists())
assertTrue(config.trustStoreFile.exists())
createRegistrationHelper().buildKeystore()
val nodeKeystore = loadKeyStore(config.nodeKeystore, config.keyStorePassword)
val sslKeystore = loadKeyStore(config.sslKeystore, config.keyStorePassword)
@ -79,9 +74,8 @@ class NetworkRegistrationHelperTest {
assertFalse(containsAlias(X509Utilities.CORDA_INTERMEDIATE_CA))
assertFalse(containsAlias(X509Utilities.CORDA_ROOT_CA))
assertFalse(containsAlias(X509Utilities.CORDA_CLIENT_TLS))
val certificateChain = getCertificateChain(X509Utilities.CORDA_CLIENT_CA)
assertEquals(3, certificateChain.size)
assertEquals(listOf("CORDA_CLIENT_CA", "CORDA_INTERMEDIATE_CA", "CORDA_ROOT_CA"), certificateChain.map { it.toX509CertHolder().subject.commonName })
val nodeCaCertChain = getCertificateChain(X509Utilities.CORDA_CLIENT_CA)
assertThat(nodeCaCertChain).containsExactly(nodeCaCert, intermediateCaCert, rootCaCert)
}
sslKeystore.run {
@ -89,46 +83,55 @@ class NetworkRegistrationHelperTest {
assertFalse(containsAlias(X509Utilities.CORDA_INTERMEDIATE_CA))
assertFalse(containsAlias(X509Utilities.CORDA_ROOT_CA))
assertTrue(containsAlias(X509Utilities.CORDA_CLIENT_TLS))
val certificateChain = getCertificateChain(X509Utilities.CORDA_CLIENT_TLS)
assertEquals(4, certificateChain.size)
assertEquals(listOf(CordaX500Name(organisation = "R3 Ltd", locality = "London", country = "GB").x500Name) + identities.map { it.x500Name },
certificateChain.map { it.toX509CertHolder().subject })
assertEquals(CordaX500Name(organisation = "R3 Ltd", locality = "London", country = "GB").x500Principal,
getX509Certificate(X509Utilities.CORDA_CLIENT_TLS).subjectX500Principal)
val nodeTlsCertChain = getCertificateChain(X509Utilities.CORDA_CLIENT_TLS)
assertThat(nodeTlsCertChain).hasSize(4)
// The TLS cert has the same subject as the node CA cert
assertThat(CordaX500Name.build((nodeTlsCertChain[0] as X509Certificate).subjectX500Principal)).isEqualTo(nodeLegalName)
assertThat(nodeTlsCertChain.drop(1)).containsExactly(nodeCaCert, intermediateCaCert, rootCaCert)
}
trustStore.run {
assertFalse(containsAlias(X509Utilities.CORDA_CLIENT_CA))
assertFalse(containsAlias(X509Utilities.CORDA_INTERMEDIATE_CA))
assertTrue(containsAlias(X509Utilities.CORDA_ROOT_CA))
val trustStoreRootCaCert = getCertificate(X509Utilities.CORDA_ROOT_CA)
assertThat(trustStoreRootCaCert).isEqualTo(rootCaCert)
}
}
@Test
fun `missing truststore`() {
assertThatThrownBy {
NetworkRegistrationHelper(config, certService).buildKeystore()
createRegistrationHelper()
}.hasMessageContaining("This file must contain the root CA cert of your compatibility zone. Please contact your CZ operator.")
.isInstanceOf(IllegalArgumentException::class.java)
}
@Test
fun `wrong root cert in truststore`() {
val someCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Foo", "MU", "GB"), Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)).cert
config.trustStoreFile.parent.createDirectories()
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, someCert)
it.save(config.trustStoreFile, config.trustStorePassword)
}
saveTrustStoreWithRootCa(createCaCert(CordaX500Name("Foo", "MU", "GB")))
val registrationHelper = createRegistrationHelper()
assertThatThrownBy {
NetworkRegistrationHelper(config, certService).buildKeystore()
registrationHelper.buildKeystore()
}.isInstanceOf(WrongRootCertException::class.java)
}
private fun mockRegistrationResponse(vararg response: Certificate): NetworkRegistrationService {
return rigorousMock<NetworkRegistrationService>().also {
private fun createRegistrationHelper(): NetworkRegistrationHelper {
val certService = rigorousMock<NetworkRegistrationService>().also {
doReturn(requestId).whenever(it).submitRequest(any())
doReturn(response).whenever(it).retrieveCertificates(eq(requestId))
doReturn(arrayOf<Certificate>(nodeCaCert, intermediateCaCert, rootCaCert)).whenever(it).retrieveCertificates(eq(requestId))
}
return NetworkRegistrationHelper(config, certService)
}
private fun saveTrustStoreWithRootCa(rootCa: X509Certificate) {
config.trustStoreFile.parent.createDirectories()
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCa)
it.save(config.trustStoreFile, config.trustStorePassword)
}
}
private fun createCaCert(name: CordaX500Name): X509Certificate {
return X509Utilities.createSelfSignedCACertificate(name, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)).cert
}
}

View File

@ -4,13 +4,11 @@ import net.corda.cordform.CordformContext
import net.corda.cordform.CordformDefinition
import net.corda.cordform.CordformNode
import net.corda.core.identity.CordaX500Name
import net.corda.core.node.services.NotaryService
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.IdentityGenerator
import net.corda.testing.node.internal.demorun.*
import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB_NAME
@ -24,7 +22,7 @@ private val notaryNames = createNotaryNames(clusterSize)
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
// NOT use this as a design to copy.
class BFTNotaryCordform : CordformDefinition() {
private val clusterName = CordaX500Name(BFTNonValidatingNotaryService.id, "BFT", "Zurich", "CH")
private val clusterName = CordaX500Name("BFT", "Zurich", "CH")
init {
nodesDirectory = Paths.get("build", "nodes", "nodesBFT")
@ -64,10 +62,10 @@ class BFTNotaryCordform : CordformDefinition() {
}
override fun setup(context: CordformContext) {
ServiceIdentityGenerator.generateToDisk(
IdentityGenerator.generateDistributedNotaryIdentity(
notaryNames.map { context.baseDirectory(it.toString()) },
clusterName,
NotaryService.constructId(validating = false, bft = true),
minCorrectReplicas(clusterSize))
minCorrectReplicas(clusterSize)
)
}
}

View File

@ -8,8 +8,7 @@ import net.corda.core.node.services.NotaryService
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.config.RaftConfig
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.IdentityGenerator
import net.corda.testing.node.internal.demorun.*
import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB_NAME
@ -24,7 +23,7 @@ private val notaryNames = createNotaryNames(3)
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
// NOT use this as a design to copy.
class RaftNotaryCordform : CordformDefinition() {
private val clusterName = CordaX500Name(RaftValidatingNotaryService.id, "Raft", "Zurich", "CH")
private val clusterName = CordaX500Name("Raft", "Zurich", "CH")
init {
nodesDirectory = Paths.get("build", "nodes", "nodesRaft")
@ -60,9 +59,9 @@ class RaftNotaryCordform : CordformDefinition() {
}
override fun setup(context: CordformContext) {
ServiceIdentityGenerator.generateToDisk(
IdentityGenerator.generateDistributedNotaryIdentity(
notaryNames.map { context.baseDirectory(it.toString()) },
clusterName,
NotaryService.constructId(validating = true, raft = true))
clusterName
)
}
}

View File

@ -29,7 +29,7 @@ dependencies {
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
// Integration test helpers
integrationTestCompile "org.assertj:assertj-core:${assertj_version}"
testCompile "org.assertj:assertj-core:$assertj_version"
integrationTestCompile "junit:junit:$junit_version"
// Jetty dependencies for NetworkMapClient test.

View File

@ -9,6 +9,7 @@ import net.corda.core.crypto.random63BitValue
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.createDirectories
import net.corda.core.internal.createDirectory
import net.corda.core.internal.uncheckedCast
@ -37,7 +38,7 @@ import net.corda.node.services.transactions.BFTSMaRt
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
import net.corda.node.utilities.AffinityExecutor
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.IdentityGenerator
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NotaryInfo
@ -125,14 +126,14 @@ data class MockNodeArgs(
* By default a single notary node is automatically started, which forms part of the network parameters for all the nodes.
* This node is available by calling [defaultNotaryNode].
*/
class MockNetwork(private val cordappPackages: List<String>,
defaultParameters: MockNetworkParameters = MockNetworkParameters(),
private val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped,
private val threadPerNode: Boolean = defaultParameters.threadPerNode,
servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = defaultParameters.servicePeerAllocationStrategy,
private val defaultFactory: (MockNodeArgs) -> MockNode = defaultParameters.defaultFactory,
initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
private val notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs) {
open class MockNetwork(private val cordappPackages: List<String>,
defaultParameters: MockNetworkParameters = MockNetworkParameters(),
private val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped,
private val threadPerNode: Boolean = defaultParameters.threadPerNode,
servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = defaultParameters.servicePeerAllocationStrategy,
private val defaultFactory: (MockNodeArgs) -> MockNode = defaultParameters.defaultFactory,
initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
private val notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs) {
/** Helper constructor for creating a [MockNetwork] with custom parameters from Java. */
@JvmOverloads
constructor(cordappPackages: List<String>, parameters: MockNetworkParameters = MockNetworkParameters()) : this(cordappPackages, defaultParameters = parameters)
@ -141,7 +142,7 @@ class MockNetwork(private val cordappPackages: List<String>,
// Apache SSHD for whatever reason registers a SFTP FileSystemProvider - which gets loaded by JimFS.
// This SFTP support loads BouncyCastle, which we want to avoid.
// Please see https://issues.apache.org/jira/browse/SSHD-736 - it's easier then to create our own fork of SSHD
SecurityUtils.setAPrioriDisabledProvider("BC", true)
SecurityUtils.setAPrioriDisabledProvider("BC", true) // XXX: Why isn't this static?
}
var nextNodeId = 0
@ -159,6 +160,7 @@ class MockNetwork(private val cordappPackages: List<String>,
throw IllegalStateException("Using more than one MockNetwork simultaneously is not supported.", e)
}
private val sharedUserCount = AtomicInteger(0)
/** A read only view of the current set of nodes. */
val nodes: List<MockNode> get() = _nodes
@ -172,32 +174,29 @@ class MockNetwork(private val cordappPackages: List<String>,
* Returns the single notary node on the network. Throws if there are none or more than one.
* @see notaryNodes
*/
val defaultNotaryNode: StartedNode<MockNode>
get() {
return when (notaryNodes.size) {
0 -> throw IllegalStateException("There are no notaries defined on the network")
1 -> notaryNodes[0]
else -> throw IllegalStateException("There is more than one notary defined on the network")
}
val defaultNotaryNode: StartedNode<MockNode> get() {
return when (notaryNodes.size) {
0 -> throw IllegalStateException("There are no notaries defined on the network")
1 -> notaryNodes[0]
else -> throw IllegalStateException("There is more than one notary defined on the network")
}
}
/**
* Return the identity of the default notary node.
* @see defaultNotaryNode
*/
val defaultNotaryIdentity: Party
get() {
return defaultNotaryNode.info.legalIdentities.singleOrNull() ?: throw IllegalStateException("Default notary has multiple identities")
}
val defaultNotaryIdentity: Party get() {
return defaultNotaryNode.info.legalIdentities.singleOrNull() ?: throw IllegalStateException("Default notary has multiple identities")
}
/**
* Return the identity of the default notary node.
* @see defaultNotaryNode
*/
val defaultNotaryIdentityAndCert: PartyAndCertificate
get() {
return defaultNotaryNode.info.legalIdentitiesAndCerts.singleOrNull() ?: throw IllegalStateException("Default notary has multiple identities")
}
val defaultNotaryIdentityAndCert: PartyAndCertificate get() {
return defaultNotaryNode.info.legalIdentitiesAndCerts.singleOrNull() ?: throw IllegalStateException("Default notary has multiple identities")
}
/**
* Because this executor is shared, we need to be careful about nodes shutting it down.
@ -222,27 +221,31 @@ class MockNetwork(private val cordappPackages: List<String>,
}
init {
filesystem.getPath("/nodes").createDirectory()
val notaryInfos = generateNotaryIdentities()
// The network parameters must be serialised before starting any of the nodes
networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos))
notaryNodes = createNotaries()
try {
filesystem.getPath("/nodes").createDirectory()
val notaryInfos = generateNotaryIdentities()
// The network parameters must be serialised before starting any of the nodes
networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos))
@Suppress("LeakingThis")
notaryNodes = createNotaries()
} catch (t: Throwable) {
stopNodes()
throw t
}
}
private fun generateNotaryIdentities(): List<NotaryInfo> {
return notarySpecs.mapIndexed { index, (name, validating) ->
val identity = ServiceIdentityGenerator.generateToDisk(
dirs = listOf(baseDirectory(nextNodeId + index)),
serviceName = name,
serviceId = "identity")
val identity = IdentityGenerator.generateNodeIdentity(baseDirectory(nextNodeId + index), name)
NotaryInfo(identity, validating)
}
}
private fun createNotaries(): List<StartedNode<MockNode>> {
return notarySpecs.map { spec ->
createNode(MockNodeParameters(legalName = spec.name, configOverrides = {
doReturn(NotaryConfig(spec.validating)).whenever(it).notary
@VisibleForTesting
internal open fun createNotaries(): List<StartedNode<MockNode>> {
return notarySpecs.map { (name, validating) ->
createNode(MockNodeParameters(legalName = name, configOverrides = {
doReturn(NotaryConfig(validating)).whenever(it).notary
}))
}
}
@ -299,7 +302,7 @@ class MockNetwork(private val cordappPackages: List<String>,
id,
serverThread,
myNotaryIdentity,
myLegalName,
configuration.myLegalName,
database).also { runOnStop += it::stop }
}
@ -457,8 +460,11 @@ class MockNetwork(private val cordappPackages: List<String>,
}
fun stopNodes() {
nodes.forEach { it.started?.dispose() }
serializationEnv.unset()
try {
nodes.forEach { it.started?.dispose() }
} finally {
serializationEnv.unset() // Must execute even if other parts of this method fail.
}
messagingNetwork.stop()
}

View File

@ -19,7 +19,6 @@ import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.services.NetworkMapCache
import net.corda.core.node.services.NotaryService
import net.corda.core.toFuture
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
@ -30,12 +29,9 @@ import net.corda.node.internal.NodeStartup
import net.corda.node.internal.StartedNode
import net.corda.node.services.Permissions
import net.corda.node.services.config.*
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.RaftNonValidatingNotaryService
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
import net.corda.node.utilities.registration.NetworkRegistrationHelper
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.IdentityGenerator
import net.corda.nodeapi.internal.addShutdownHook
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.config.parseAs
@ -245,9 +241,9 @@ class DriverDSLImpl(
}
private enum class ClusterType(val validating: Boolean, val clusterName: CordaX500Name) {
VALIDATING_RAFT(true, CordaX500Name(RaftValidatingNotaryService.id, "Raft", "Zurich", "CH")),
NON_VALIDATING_RAFT(false, CordaX500Name(RaftNonValidatingNotaryService.id, "Raft", "Zurich", "CH")),
NON_VALIDATING_BFT(false, CordaX500Name(BFTNonValidatingNotaryService.id, "BFT", "Zurich", "CH"))
VALIDATING_RAFT(true, CordaX500Name("Raft", "Zurich", "CH")),
NON_VALIDATING_RAFT(false, CordaX500Name("Raft", "Zurich", "CH")),
NON_VALIDATING_BFT(false, CordaX500Name("BFT", "Zurich", "CH"))
}
internal fun startCordformNodes(cordforms: List<CordformNode>): CordaFuture<*> {
@ -270,24 +266,15 @@ class DriverDSLImpl(
clusterNodes.put(ClusterType.NON_VALIDATING_BFT, name)
} else {
// We have all we need here to generate the identity for single node notaries
val identity = ServiceIdentityGenerator.generateToDisk(
dirs = listOf(baseDirectory(name)),
serviceName = name,
serviceId = "identity"
)
val identity = IdentityGenerator.generateNodeIdentity(baseDirectory(name), legalName = name)
notaryInfos += NotaryInfo(identity, notaryConfig.validating)
}
}
clusterNodes.asMap().forEach { type, nodeNames ->
val identity = ServiceIdentityGenerator.generateToDisk(
val identity = IdentityGenerator.generateDistributedNotaryIdentity(
dirs = nodeNames.map { baseDirectory(it) },
serviceName = type.clusterName,
serviceId = NotaryService.constructId(
validating = type.validating,
raft = type in setOf(VALIDATING_RAFT, NON_VALIDATING_RAFT),
bft = type == ClusterType.NON_VALIDATING_BFT
)
notaryName = type.clusterName
)
notaryInfos += NotaryInfo(identity, type.validating)
}
@ -369,20 +356,11 @@ class DriverDSLImpl(
private fun generateNotaryIdentities(): List<NotaryInfo> {
return notarySpecs.map { spec ->
val identity = if (spec.cluster == null) {
ServiceIdentityGenerator.generateToDisk(
dirs = listOf(baseDirectory(spec.name)),
serviceName = spec.name,
serviceId = "identity",
customRootCert = compatibilityZone?.rootCert
)
IdentityGenerator.generateNodeIdentity(baseDirectory(spec.name), spec.name, compatibilityZone?.rootCert)
} else {
ServiceIdentityGenerator.generateToDisk(
IdentityGenerator.generateDistributedNotaryIdentity(
dirs = generateNodeNames(spec).map { baseDirectory(it) },
serviceName = spec.name,
serviceId = NotaryService.constructId(
validating = spec.validating,
raft = spec.cluster is ClusterSpec.Raft
),
notaryName = spec.name,
customRootCert = compatibilityZone?.rootCert
)
}

View File

@ -0,0 +1,18 @@
package net.corda.testing.node
import net.corda.core.serialization.internal.effectiveSerializationEnv
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test
class MockNetworkTests {
@Test
fun `does not leak serialization env if init fails`() {
val e = Exception("didn't work")
assertThatThrownBy {
object : MockNetwork(emptyList(), initialiseSerialization = true) {
override fun createNotaries() = throw e
}
}.isSameAs(e)
assertThatThrownBy { effectiveSerializationEnv }.isInstanceOf(IllegalStateException::class.java)
}
}

View File

@ -10,6 +10,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.cert
import net.corda.core.internal.unspecifiedCountry
import net.corda.core.internal.x500Name
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort
@ -91,13 +92,13 @@ fun getTestPartyAndCertificate(party: Party): PartyAndCertificate {
val trustRoot: X509CertificateHolder = DEV_TRUST_ROOT
val intermediate: CertificateAndKeyPair = DEV_CA
val nodeCaName = party.name.copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN)
val nodeCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val nodeCaCert = X509Utilities.createCertificate(
CertificateType.NODE_CA,
intermediate.certificate,
intermediate.keyPair,
nodeCaName,
party.name,
nodeCaKeyPair.public,
nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, party.name.x500Name))), arrayOf()))

View File

@ -13,7 +13,7 @@ import net.corda.demobench.pty.R3Pty
import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NotaryInfo
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.IdentityGenerator
import tornadofx.*
import java.io.IOException
import java.lang.management.ManagementFactory
@ -153,10 +153,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
// Generate notary identity and save it into node's directory. This identity will be used in network parameters.
private fun getNotaryIdentity(config: NodeConfigWrapper): Party {
return ServiceIdentityGenerator.generateToDisk(
dirs = listOf(config.nodeDir),
serviceName = config.nodeConfig.myLegalName,
serviceId = "identity")
return IdentityGenerator.generateNodeIdentity(config.nodeDir, config.nodeConfig.myLegalName)
}
fun reset() {