mirror of
https://github.com/corda/corda.git
synced 2025-06-05 09:00:53 +00:00
Change party to hold an X.500 name
Change the legal name of parties to be an X500 name. This ensures that we aren't converting between common names and X500 names in various places, eliminating substantial scope for error in the conversion process. As a result, all node names must now be full X500 names, which has impact on most configurations.
This commit is contained in:
parent
b64e7f51f6
commit
25dbac0f07
@ -17,6 +17,8 @@ import net.corda.core.serialization.OpaqueBytes
|
|||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||||
|
import org.bouncycastle.asn1.ASN1InputStream
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -32,22 +34,27 @@ object JacksonSupport {
|
|||||||
// If you change this API please update the docs in the docsite (json.rst)
|
// If you change this API please update the docs in the docsite (json.rst)
|
||||||
|
|
||||||
interface PartyObjectMapper {
|
interface PartyObjectMapper {
|
||||||
|
@Deprecated("Use partyFromX500Name instead")
|
||||||
fun partyFromName(partyName: String): Party?
|
fun partyFromName(partyName: String): Party?
|
||||||
|
fun partyFromPrincipal(principal: X500Name): Party?
|
||||||
fun partyFromKey(owningKey: PublicKey): Party?
|
fun partyFromKey(owningKey: PublicKey): Party?
|
||||||
}
|
}
|
||||||
|
|
||||||
class RpcObjectMapper(val rpc: CordaRPCOps, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
|
class RpcObjectMapper(val rpc: CordaRPCOps, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
|
||||||
override fun partyFromName(partyName: String): Party? = rpc.partyFromName(partyName)
|
override fun partyFromName(partyName: String): Party? = rpc.partyFromName(partyName)
|
||||||
|
override fun partyFromPrincipal(principal: X500Name): Party? = rpc.partyFromX500Name(principal)
|
||||||
override fun partyFromKey(owningKey: PublicKey): Party? = rpc.partyFromKey(owningKey)
|
override fun partyFromKey(owningKey: PublicKey): Party? = rpc.partyFromKey(owningKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
class IdentityObjectMapper(val identityService: IdentityService, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
|
class IdentityObjectMapper(val identityService: IdentityService, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
|
||||||
override fun partyFromName(partyName: String): Party? = identityService.partyFromName(partyName)
|
override fun partyFromName(partyName: String): Party? = identityService.partyFromName(partyName)
|
||||||
|
override fun partyFromPrincipal(principal: X500Name): Party? = identityService.partyFromX500Name(principal)
|
||||||
override fun partyFromKey(owningKey: PublicKey): Party? = identityService.partyFromKey(owningKey)
|
override fun partyFromKey(owningKey: PublicKey): Party? = identityService.partyFromKey(owningKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoPartyObjectMapper(factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
|
class NoPartyObjectMapper(factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
|
||||||
override fun partyFromName(partyName: String): Party? = throw UnsupportedOperationException()
|
override fun partyFromName(partyName: String): Party? = throw UnsupportedOperationException()
|
||||||
|
override fun partyFromPrincipal(principal: X500Name): Party? = throw UnsupportedOperationException()
|
||||||
override fun partyFromKey(owningKey: PublicKey): Party? = throw UnsupportedOperationException()
|
override fun partyFromKey(owningKey: PublicKey): Party? = throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +92,10 @@ object JacksonSupport {
|
|||||||
// For OpaqueBytes
|
// For OpaqueBytes
|
||||||
addDeserializer(OpaqueBytes::class.java, OpaqueBytesDeserializer)
|
addDeserializer(OpaqueBytes::class.java, OpaqueBytesDeserializer)
|
||||||
addSerializer(OpaqueBytes::class.java, OpaqueBytesSerializer)
|
addSerializer(OpaqueBytes::class.java, OpaqueBytesSerializer)
|
||||||
|
|
||||||
|
// For X.500 distinguished names
|
||||||
|
addDeserializer(X500Name::class.java, X500NameDeserializer)
|
||||||
|
addSerializer(X500Name::class.java, X500NameSerializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +147,7 @@ object JacksonSupport {
|
|||||||
|
|
||||||
object PartySerializer : JsonSerializer<Party>() {
|
object PartySerializer : JsonSerializer<Party>() {
|
||||||
override fun serialize(obj: Party, generator: JsonGenerator, provider: SerializerProvider) {
|
override fun serialize(obj: Party, generator: JsonGenerator, provider: SerializerProvider) {
|
||||||
generator.writeString(obj.name)
|
generator.writeString(obj.name.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,8 +158,28 @@ object JacksonSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val mapper = parser.codec as PartyObjectMapper
|
val mapper = parser.codec as PartyObjectMapper
|
||||||
// TODO this needs to use some industry identifier(s) not just these human readable names
|
val principal = X500Name(parser.text)
|
||||||
return mapper.partyFromName(parser.text) ?: throw JsonParseException(parser, "Could not find a Party with name ${parser.text}")
|
return mapper.partyFromPrincipal(principal) ?: throw JsonParseException(parser, "Could not find a Party with name ${principal}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object X500NameSerializer : JsonSerializer<X500Name>() {
|
||||||
|
override fun serialize(obj: X500Name, generator: JsonGenerator, provider: SerializerProvider) {
|
||||||
|
generator.writeString(obj.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object X500NameDeserializer : JsonDeserializer<X500Name>() {
|
||||||
|
override fun deserialize(parser: JsonParser, context: DeserializationContext): X500Name {
|
||||||
|
if (parser.currentToken == JsonToken.FIELD_NAME) {
|
||||||
|
parser.nextToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
X500Name(parser.text)
|
||||||
|
} catch(ex: IllegalArgumentException) {
|
||||||
|
throw JsonParseException(parser, "Invalid X.500 name ${parser.text}: ${ex.message}", ex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ import net.corda.testing.expect
|
|||||||
import net.corda.testing.expectEvents
|
import net.corda.testing.expectEvents
|
||||||
import net.corda.testing.node.DriverBasedTest
|
import net.corda.testing.node.DriverBasedTest
|
||||||
import net.corda.testing.sequence
|
import net.corda.testing.sequence
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
|||||||
lateinit var transactions: Observable<SignedTransaction>
|
lateinit var transactions: Observable<SignedTransaction>
|
||||||
lateinit var vaultUpdates: Observable<Vault.Update>
|
lateinit var vaultUpdates: Observable<Vault.Update>
|
||||||
lateinit var networkMapUpdates: Observable<NetworkMapCache.MapChange>
|
lateinit var networkMapUpdates: Observable<NetworkMapCache.MapChange>
|
||||||
lateinit var newNode: (String) -> NodeInfo
|
lateinit var newNode: (X500Name) -> NodeInfo
|
||||||
|
|
||||||
override fun setup() = driver {
|
override fun setup() = driver {
|
||||||
val cashUser = User("user1", "test", permissions = setOf(
|
val cashUser = User("user1", "test", permissions = setOf(
|
||||||
|
@ -20,7 +20,6 @@ import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl
|
|||||||
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory
|
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory
|
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory
|
||||||
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ
|
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -75,7 +74,7 @@ abstract class AbstractClientRPCTest {
|
|||||||
override val users: List<User> get() = listOf(rpcUser)
|
override val users: List<User> get() = listOf(rpcUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
val dispatcher = object : RPCDispatcher(rpcImpl, userService, X500Name(ALICE.name)) {
|
val dispatcher = object : RPCDispatcher(rpcImpl, userService, ALICE.name) {
|
||||||
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
override fun send(data: SerializedBytes<*>, toAddress: String) {
|
||||||
val msg = serverSession.createMessage(false).apply {
|
val msg = serverSession.createMessage(false).apply {
|
||||||
writeBodyBufferBytes(data.bytes)
|
writeBodyBufferBytes(data.bytes)
|
||||||
@ -100,4 +99,4 @@ abstract class AbstractClientRPCTest {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ package net.corda.core.crypto
|
|||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,7 +17,7 @@ abstract class AbstractParty(val owningKey: PublicKey) {
|
|||||||
|
|
||||||
override fun hashCode(): Int = owningKey.hashCode()
|
override fun hashCode(): Int = owningKey.hashCode()
|
||||||
abstract fun toAnonymous(): AnonymousParty
|
abstract fun toAnonymous(): AnonymousParty
|
||||||
abstract fun nameOrNull(): String?
|
abstract fun nameOrNull(): X500Name?
|
||||||
|
|
||||||
abstract fun ref(bytes: OpaqueBytes): PartyAndReference
|
abstract fun ref(bytes: OpaqueBytes): PartyAndReference
|
||||||
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))
|
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.core.crypto
|
|||||||
|
|
||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -13,7 +14,7 @@ class AnonymousParty(owningKey: PublicKey) : AbstractParty(owningKey) {
|
|||||||
// can put in the key and actual name
|
// can put in the key and actual name
|
||||||
override fun toString() = "${owningKey.toBase58String()} <Anonymous>"
|
override fun toString() = "${owningKey.toBase58String()} <Anonymous>"
|
||||||
|
|
||||||
override fun nameOrNull(): String? = null
|
override fun nameOrNull(): X500Name? = null
|
||||||
|
|
||||||
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes)
|
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes)
|
||||||
override fun toAnonymous() = this
|
override fun toAnonymous() = this
|
||||||
|
@ -12,7 +12,8 @@ import java.security.PublicKey
|
|||||||
* cryptographic public key primitives into a tree structure.
|
* cryptographic public key primitives into a tree structure.
|
||||||
*
|
*
|
||||||
* For example: Alice has two key pairs (pub1/priv1 and pub2/priv2), and wants to be able to sign transactions with either of them.
|
* For example: Alice has two key pairs (pub1/priv1 and pub2/priv2), and wants to be able to sign transactions with either of them.
|
||||||
* Her advertised [Party] then has a legal [name] "Alice" and an [owningKey] "pub1 or pub2".
|
* Her advertised [Party] then has a legal X.500 [name] "CN=Alice Corp,O=Alice Corp,L=London,C=UK" and an [owningKey]
|
||||||
|
* "pub1 or pub2".
|
||||||
*
|
*
|
||||||
* [Party] is also used for service identities. E.g. Alice may also be running an interest rate oracle on her Corda node,
|
* [Party] is also used for service identities. E.g. Alice may also be running an interest rate oracle on her Corda node,
|
||||||
* which requires a separate signing key (and an identifying name). Services can also be distributed – run by a coordinated
|
* which requires a separate signing key (and an identifying name). Services can also be distributed – run by a coordinated
|
||||||
@ -23,11 +24,10 @@ import java.security.PublicKey
|
|||||||
*
|
*
|
||||||
* @see CompositeKey
|
* @see CompositeKey
|
||||||
*/
|
*/
|
||||||
class Party(val name: String, owningKey: PublicKey) : AbstractParty(owningKey) {
|
class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) {
|
||||||
constructor(name: X500Name, owningKey: PublicKey) : this(name.toString(), owningKey)
|
|
||||||
override fun toAnonymous(): AnonymousParty = AnonymousParty(owningKey)
|
override fun toAnonymous(): AnonymousParty = AnonymousParty(owningKey)
|
||||||
override fun toString() = "${owningKey.toBase58String()} ($name)"
|
override fun toString() = "${owningKey.toBase58String()} ($name)"
|
||||||
override fun nameOrNull(): String? = name
|
override fun nameOrNull(): X500Name? = name
|
||||||
|
|
||||||
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this.toAnonymous(), bytes)
|
override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this.toAnonymous(), bytes)
|
||||||
}
|
}
|
||||||
|
@ -109,9 +109,8 @@ object X509Utilities {
|
|||||||
/**
|
/**
|
||||||
* Return a bogus X509 for dev purposes. Use [getX509Name] for something more real.
|
* Return a bogus X509 for dev purposes. Use [getX509Name] for something more real.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("Full legal names should be specified in all configurations")
|
||||||
fun getDevX509Name(commonName: String): X500Name {
|
fun getDevX509Name(commonName: String): X500Name {
|
||||||
// Check that we haven't been accidentally given a full X500 distinguished name
|
|
||||||
require(!commonName.startsWith("CN=")) { "Provided common name must not start \"CN=\"" }
|
|
||||||
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
||||||
nameBuilder.addRDN(BCStyle.CN, commonName)
|
nameBuilder.addRDN(BCStyle.CN, commonName)
|
||||||
nameBuilder.addRDN(BCStyle.O, "R3")
|
nameBuilder.addRDN(BCStyle.O, "R3")
|
||||||
@ -271,16 +270,6 @@ object X509Utilities {
|
|||||||
*/
|
*/
|
||||||
data class CACertAndKey(val certificate: X509Certificate, val keyPair: KeyPair)
|
data class CACertAndKey(val certificate: X509Certificate, val keyPair: KeyPair)
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a de novo root self-signed X509 v3 CA cert and [KeyPair].
|
|
||||||
* @param commonName The Common (CN) field of the cert Subject will be populated with the domain string
|
|
||||||
* @return A data class is returned containing the new root CA Cert and its [KeyPair] for signing downstream certificates.
|
|
||||||
* Note the generated certificate tree is capped at max depth of 2 to be in line with commercially available certificates
|
|
||||||
*/
|
|
||||||
@Deprecated("Use [createSelfSignedCACert(X500Name)] instead, specifying full legal name")
|
|
||||||
fun createSelfSignedCACert(commonName: String): CACertAndKey = createSelfSignedCACert(getDevX509Name(commonName))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a de novo root self-signed X509 v3 CA cert and [KeyPair].
|
* Create a de novo root self-signed X509 v3 CA cert and [KeyPair].
|
||||||
* @param subject the cert Subject will be populated with the domain string
|
* @param subject the cert Subject will be populated with the domain string
|
||||||
@ -324,18 +313,6 @@ object X509Utilities {
|
|||||||
return CACertAndKey(cert, keyPair)
|
return CACertAndKey(cert, keyPair)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a de novo root intermediate X509 v3 CA cert and KeyPair.
|
|
||||||
* @param commonName The Common (CN) field of the cert Subject will be populated with the domain string
|
|
||||||
* @param certificateAuthority The Public certificate and KeyPair of the root CA certificate above this used to sign it
|
|
||||||
* @return A data class is returned containing the new intermediate CA Cert and its KeyPair for signing downstream certificates.
|
|
||||||
* Note the generated certificate tree is capped at max depth of 1 below this to be in line with commercially available certificates
|
|
||||||
*/
|
|
||||||
@Deprecated("Use [createIntermediateCert(X500Name, CACertAndKey)] instead, specifying full legal name")
|
|
||||||
fun createIntermediateCert(commonName: String,
|
|
||||||
certificateAuthority: CACertAndKey): CACertAndKey
|
|
||||||
= createIntermediateCert(getDevX509Name(commonName), certificateAuthority)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a de novo root intermediate X509 v3 CA cert and KeyPair.
|
* Create a de novo root intermediate X509 v3 CA cert and KeyPair.
|
||||||
* @param subject subject of the generated certificate.
|
* @param subject subject of the generated certificate.
|
||||||
@ -547,10 +524,14 @@ object X509Utilities {
|
|||||||
storePassword: String,
|
storePassword: String,
|
||||||
keyPassword: String,
|
keyPassword: String,
|
||||||
trustStoreFilePath: Path,
|
trustStoreFilePath: Path,
|
||||||
trustStorePassword: String
|
trustStorePassword: String,
|
||||||
|
// TODO: Remove these defaults - live calls should always specify these
|
||||||
|
// and tests should use [getTestX509Name]
|
||||||
|
rootCaName: X500Name = getDevX509Name("Corda Node Root CA"),
|
||||||
|
intermediateCaName: X500Name = getDevX509Name("Corda Node Intermediate CA")
|
||||||
): KeyStore {
|
): KeyStore {
|
||||||
val rootCA = createSelfSignedCACert(getDevX509Name("Corda Node Root CA"))
|
val rootCA = createSelfSignedCACert(rootCaName)
|
||||||
val intermediateCA = createIntermediateCert(getDevX509Name("Corda Node Intermediate CA"), rootCA)
|
val intermediateCA = createIntermediateCert(intermediateCaName, rootCA)
|
||||||
|
|
||||||
val keyPass = keyPassword.toCharArray()
|
val keyPass = keyPassword.toCharArray()
|
||||||
val keyStore = loadOrCreateKeyStore(keyStoreFilePath, storePassword)
|
val keyStore = loadOrCreateKeyStore(keyStoreFilePath, storePassword)
|
||||||
@ -591,24 +572,6 @@ object X509Utilities {
|
|||||||
return CACertAndKey(cert, KeyPair(cert.publicKey, key))
|
return CACertAndKey(cert, KeyPair(cert.publicKey, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An all in wrapper to manufacture a server certificate and keys all stored in a KeyStore suitable for running TLS on the local machine
|
|
||||||
* @param keyStoreFilePath KeyStore path to save output to
|
|
||||||
* @param storePassword access password for KeyStore
|
|
||||||
* @param keyPassword PrivateKey access password for the generated keys.
|
|
||||||
* It is recommended that this is the same as the storePassword as most TLS libraries assume they are the same.
|
|
||||||
* @param caKeyStore KeyStore containing CA keys generated by createCAKeyStoreAndTrustStore
|
|
||||||
* @param caKeyPassword password to unlock private keys in the CA KeyStore
|
|
||||||
* @return The KeyStore created containing a private key, certificate chain and root CA public cert for use in TLS applications
|
|
||||||
*/
|
|
||||||
fun createKeystoreForSSL(keyStoreFilePath: Path,
|
|
||||||
storePassword: String,
|
|
||||||
keyPassword: String,
|
|
||||||
caKeyStore: KeyStore,
|
|
||||||
caKeyPassword: String,
|
|
||||||
commonName: String): KeyStore = createKeystoreForSSL(keyStoreFilePath, storePassword, keyPassword,
|
|
||||||
caKeyStore, caKeyPassword, getDevX509Name(commonName))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An all in wrapper to manufacture a server certificate and keys all stored in a KeyStore suitable for running TLS on the local machine
|
* An all in wrapper to manufacture a server certificate and keys all stored in a KeyStore suitable for running TLS on the local machine
|
||||||
* @param keyStoreFilePath KeyStore path to save output to
|
* @param keyStoreFilePath KeyStore path to save output to
|
||||||
|
@ -236,6 +236,7 @@ interface CordaRPCOps : RPCOps {
|
|||||||
/**
|
/**
|
||||||
* Returns the [Party] with the given name as it's [Party.name]
|
* Returns the [Party] with the given name as it's [Party.name]
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("Use partyFromX500Name instead")
|
||||||
fun partyFromName(name: String): Party?
|
fun partyFromName(name: String): Party?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,8 +3,8 @@ package net.corda.core.node.services
|
|||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.crypto.AnonymousParty
|
import net.corda.core.crypto.AnonymousParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import java.security.PublicKey
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import java.security.PublicKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports
|
* An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports
|
||||||
@ -25,6 +25,7 @@ interface IdentityService {
|
|||||||
// but for now this is not supported.
|
// but for now this is not supported.
|
||||||
|
|
||||||
fun partyFromKey(key: PublicKey): Party?
|
fun partyFromKey(key: PublicKey): Party?
|
||||||
|
@Deprecated("Use partyFromX500Name")
|
||||||
fun partyFromName(name: String): Party?
|
fun partyFromName(name: String): Party?
|
||||||
fun partyFromX500Name(principal: X500Name): Party?
|
fun partyFromX500Name(principal: X500Name): Party?
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.Party
|
|||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.randomOrNull
|
import net.corda.core.randomOrNull
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ interface NetworkMapCache {
|
|||||||
fun getRecommended(type: ServiceType, contract: Contract, vararg party: Party): NodeInfo? = getNodesWithService(type).firstOrNull()
|
fun getRecommended(type: ServiceType, contract: Contract, vararg party: Party): NodeInfo? = getNodesWithService(type).firstOrNull()
|
||||||
|
|
||||||
/** Look up the node info for a legal name. */
|
/** Look up the node info for a legal name. */
|
||||||
fun getNodeByLegalName(name: String): NodeInfo? = partyNodes.singleOrNull { it.legalIdentity.name == name }
|
fun getNodeByLegalName(principal: X500Name): NodeInfo? = partyNodes.singleOrNull { it.legalIdentity.name == principal }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In general, nodes can advertise multiple identities: a legal identity, and separate identities for each of
|
* In general, nodes can advertise multiple identities: a legal identity, and separate identities for each of
|
||||||
@ -82,9 +83,9 @@ interface NetworkMapCache {
|
|||||||
fun getPartyInfo(party: Party): PartyInfo?
|
fun getPartyInfo(party: Party): PartyInfo?
|
||||||
|
|
||||||
/** Gets a notary identity by the given name. */
|
/** Gets a notary identity by the given name. */
|
||||||
fun getNotary(name: String): Party? {
|
fun getNotary(principal: X500Name): Party? {
|
||||||
val notaryNode = notaryNodes.randomOrNull {
|
val notaryNode = notaryNodes.randomOrNull {
|
||||||
it.advertisedServices.any { it.info.type.isSubTypeOf(ServiceType.notary) && it.info.name == name }
|
it.advertisedServices.any { it.info.type.isSubTypeOf(ServiceType.notary) && it.info.name == principal }
|
||||||
}
|
}
|
||||||
return notaryNode?.notaryIdentity
|
return notaryNode?.notaryIdentity
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,15 @@ import org.bouncycastle.asn1.x500.X500Name
|
|||||||
* grouping identifier for nodes collectively running a distributed service.
|
* grouping identifier for nodes collectively running a distributed service.
|
||||||
*/
|
*/
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class ServiceInfo(val type: ServiceType, val name: String? = null) {
|
data class ServiceInfo(val type: ServiceType, val name: X500Name? = null) {
|
||||||
constructor(type: ServiceType, name: X500Name?) : this(type, name?.toString())
|
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(encoded: String): ServiceInfo {
|
fun parse(encoded: String): ServiceInfo {
|
||||||
val parts = encoded.split("|")
|
val parts = encoded.split("|")
|
||||||
require(parts.size in 1..2) { "Invalid number of elements found" }
|
require(parts.size in 1..2) { "Invalid number of elements found" }
|
||||||
val type = ServiceType.parse(parts[0])
|
val type = ServiceType.parse(parts[0])
|
||||||
val name = parts.getOrNull(1)
|
val name = parts.getOrNull(1)
|
||||||
return ServiceInfo(type, name)
|
val principal = name?.let { X500Name(it) }
|
||||||
|
return ServiceInfo(type, principal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import net.corda.core.node.services.vault.QueryCriteria.AndComposition
|
|||||||
import net.corda.core.node.services.vault.QueryCriteria.OrComposition
|
import net.corda.core.node.services.vault.QueryCriteria.OrComposition
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -26,10 +27,10 @@ sealed class QueryCriteria {
|
|||||||
val status: Vault.StateStatus = Vault.StateStatus.UNCONSUMED,
|
val status: Vault.StateStatus = Vault.StateStatus.UNCONSUMED,
|
||||||
val stateRefs: List<StateRef>? = null,
|
val stateRefs: List<StateRef>? = null,
|
||||||
val contractStateTypes: Set<Class<out ContractState>>? = null,
|
val contractStateTypes: Set<Class<out ContractState>>? = null,
|
||||||
val notaryName: List<String>? = null,
|
val notaryName: List<X500Name>? = null,
|
||||||
val includeSoftlockedStates: Boolean? = true,
|
val includeSoftlockedStates: Boolean? = true,
|
||||||
val timeCondition: Logical<TimeInstantType, Array<Instant>>? = null,
|
val timeCondition: Logical<TimeInstantType, Array<Instant>>? = null,
|
||||||
val participantIdentities: List<String>? = null) : QueryCriteria()
|
val participantIdentities: List<X500Name>? = null) : QueryCriteria()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LinearStateQueryCriteria: provides query by attributes defined in [VaultSchema.VaultLinearState]
|
* LinearStateQueryCriteria: provides query by attributes defined in [VaultSchema.VaultLinearState]
|
||||||
@ -38,7 +39,7 @@ sealed class QueryCriteria {
|
|||||||
val linearId: List<UniqueIdentifier>? = null,
|
val linearId: List<UniqueIdentifier>? = null,
|
||||||
val latestOnly: Boolean? = true,
|
val latestOnly: Boolean? = true,
|
||||||
val dealRef: List<String>? = null,
|
val dealRef: List<String>? = null,
|
||||||
val dealPartyName: List<String>? = null) : QueryCriteria()
|
val dealPartyName: List<X500Name>? = null) : QueryCriteria()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FungibleStateQueryCriteria: provides query by attributes defined in [VaultSchema.VaultFungibleState]
|
* FungibleStateQueryCriteria: provides query by attributes defined in [VaultSchema.VaultFungibleState]
|
||||||
@ -48,11 +49,11 @@ sealed class QueryCriteria {
|
|||||||
* [Commodity] as used in [CommodityContract] state
|
* [Commodity] as used in [CommodityContract] state
|
||||||
*/
|
*/
|
||||||
data class FungibleAssetQueryCriteria @JvmOverloads constructor(
|
data class FungibleAssetQueryCriteria @JvmOverloads constructor(
|
||||||
val ownerIdentity: List<String>? = null,
|
val ownerIdentity: List<X500Name>? = null,
|
||||||
val quantity: Logical<*,Long>? = null,
|
val quantity: Logical<*,Long>? = null,
|
||||||
val tokenType: List<Class<out Any>>? = null,
|
val tokenType: List<Class<out Any>>? = null,
|
||||||
val tokenValue: List<String>? = null,
|
val tokenValue: List<String>? = null,
|
||||||
val issuerPartyName: List<String>? = null,
|
val issuerPartyName: List<X500Name>? = null,
|
||||||
val issuerRef: List<OpaqueBytes>? = null,
|
val issuerRef: List<OpaqueBytes>? = null,
|
||||||
val exitKeyIdentity: List<String>? = null) : QueryCriteria()
|
val exitKeyIdentity: List<String>? = null) : QueryCriteria()
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.core.crypto
|
|||||||
|
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.testing.MEGA_CORP
|
import net.corda.testing.MEGA_CORP
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.bouncycastle.asn1.x509.GeneralName
|
import org.bouncycastle.asn1.x509.GeneralName
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@ -31,7 +32,7 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create valid self-signed CA certificate`() {
|
fun `create valid self-signed CA certificate`() {
|
||||||
val caCertAndKey = X509Utilities.createSelfSignedCACert(X500Name("CN=Test Cert,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
val caCertAndKey = X509Utilities.createSelfSignedCACert(getTestX509Name("Test Cert"))
|
||||||
assertTrue { caCertAndKey.certificate.subjectDN.name.contains("CN=Test Cert") } // using our subject common name
|
assertTrue { caCertAndKey.certificate.subjectDN.name.contains("CN=Test Cert") } // using our subject common name
|
||||||
assertEquals(caCertAndKey.certificate.issuerDN, caCertAndKey.certificate.subjectDN) //self-signed
|
assertEquals(caCertAndKey.certificate.issuerDN, caCertAndKey.certificate.subjectDN) //self-signed
|
||||||
caCertAndKey.certificate.checkValidity(Date()) // throws on verification problems
|
caCertAndKey.certificate.checkValidity(Date()) // throws on verification problems
|
||||||
@ -43,7 +44,7 @@ class X509UtilitiesTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `load and save a PEM file certificate`() {
|
fun `load and save a PEM file certificate`() {
|
||||||
val tmpCertificateFile = tempFile("cacert.pem")
|
val tmpCertificateFile = tempFile("cacert.pem")
|
||||||
val caCertAndKey = X509Utilities.createSelfSignedCACert(X500Name("CN=Test Cert,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
val caCertAndKey = X509Utilities.createSelfSignedCACert(getTestX509Name("Test Cert"))
|
||||||
X509Utilities.saveCertificateAsPEMFile(caCertAndKey.certificate, tmpCertificateFile)
|
X509Utilities.saveCertificateAsPEMFile(caCertAndKey.certificate, tmpCertificateFile)
|
||||||
val readCertificate = X509Utilities.loadCertificateFromPEMFile(tmpCertificateFile)
|
val readCertificate = X509Utilities.loadCertificateFromPEMFile(tmpCertificateFile)
|
||||||
assertEquals(caCertAndKey.certificate, readCertificate)
|
assertEquals(caCertAndKey.certificate, readCertificate)
|
||||||
@ -51,8 +52,8 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create valid server certificate chain`() {
|
fun `create valid server certificate chain`() {
|
||||||
val caCertAndKey = X509Utilities.createSelfSignedCACert(X500Name("CN=Test CA Cert,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
val caCertAndKey = X509Utilities.createSelfSignedCACert(getTestX509Name("Test CA Cert"))
|
||||||
val subjectDN = X500Name("CN=Server Cert,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")
|
val subjectDN = getTestX509Name("Server Cert")
|
||||||
val keyPair = X509Utilities.generateECDSAKeyPairForSSL()
|
val keyPair = X509Utilities.generateECDSAKeyPairForSSL()
|
||||||
val serverCert = X509Utilities.createServerCert(subjectDN, keyPair.public, caCertAndKey, listOf("alias name"), listOf("10.0.0.54"))
|
val serverCert = X509Utilities.createServerCert(subjectDN, keyPair.public, caCertAndKey, listOf("alias name"), listOf("10.0.0.54"))
|
||||||
assertTrue { serverCert.subjectDN.name.contains("CN=Server Cert") } // using our subject common name
|
assertTrue { serverCert.subjectDN.name.contains("CN=Server Cert") } // using our subject common name
|
||||||
@ -139,7 +140,7 @@ class X509UtilitiesTest {
|
|||||||
val caCertAndKey = X509Utilities.loadCertificateAndKey(caKeyStore, "cakeypass", X509Utilities.CORDA_INTERMEDIATE_CA_PRIVATE_KEY)
|
val caCertAndKey = X509Utilities.loadCertificateAndKey(caKeyStore, "cakeypass", X509Utilities.CORDA_INTERMEDIATE_CA_PRIVATE_KEY)
|
||||||
|
|
||||||
// Generate server cert and private key and populate another keystore suitable for SSL
|
// Generate server cert and private key and populate another keystore suitable for SSL
|
||||||
X509Utilities.createKeystoreForSSL(tmpServerKeyStore, "serverstorepass", "serverkeypass", caKeyStore, "cakeypass", X500Name(MEGA_CORP.name))
|
X509Utilities.createKeystoreForSSL(tmpServerKeyStore, "serverstorepass", "serverkeypass", caKeyStore, "cakeypass", MEGA_CORP.name)
|
||||||
|
|
||||||
// Load back server certificate
|
// Load back server certificate
|
||||||
val serverKeyStore = X509Utilities.loadKeyStore(tmpServerKeyStore, "serverstorepass")
|
val serverKeyStore = X509Utilities.loadKeyStore(tmpServerKeyStore, "serverstorepass")
|
||||||
@ -148,7 +149,7 @@ class X509UtilitiesTest {
|
|||||||
serverCertAndKey.certificate.checkValidity(Date())
|
serverCertAndKey.certificate.checkValidity(Date())
|
||||||
serverCertAndKey.certificate.verify(caCertAndKey.certificate.publicKey)
|
serverCertAndKey.certificate.verify(caCertAndKey.certificate.publicKey)
|
||||||
|
|
||||||
assertTrue { serverCertAndKey.certificate.subjectDN.name.contains(X500Name(MEGA_CORP.name).commonName) }
|
assertTrue { serverCertAndKey.certificate.subjectDN.name.contains(MEGA_CORP.name.commonName) }
|
||||||
|
|
||||||
// Now sign something with private key and verify against certificate public key
|
// Now sign something with private key and verify against certificate public key
|
||||||
val testData = "123456".toByteArray()
|
val testData = "123456".toByteArray()
|
||||||
@ -176,7 +177,7 @@ class X509UtilitiesTest {
|
|||||||
"trustpass")
|
"trustpass")
|
||||||
|
|
||||||
// Generate server cert and private key and populate another keystore suitable for SSL
|
// Generate server cert and private key and populate another keystore suitable for SSL
|
||||||
val keyStore = X509Utilities.createKeystoreForSSL(tmpServerKeyStore, "serverstorepass", "serverstorepass", caKeyStore, "cakeypass", X500Name(MEGA_CORP.name))
|
val keyStore = X509Utilities.createKeystoreForSSL(tmpServerKeyStore, "serverstorepass", "serverstorepass", caKeyStore, "cakeypass", MEGA_CORP.name)
|
||||||
val trustStore = X509Utilities.loadKeyStore(tmpTrustStore, "trustpass")
|
val trustStore = X509Utilities.loadKeyStore(tmpTrustStore, "trustpass")
|
||||||
|
|
||||||
val context = SSLContext.getInstance("TLS")
|
val context = SSLContext.getInstance("TLS")
|
||||||
@ -249,7 +250,7 @@ class X509UtilitiesTest {
|
|||||||
val peerChain = clientSocket.session.peerCertificates
|
val peerChain = clientSocket.session.peerCertificates
|
||||||
val peerX500Principal = (peerChain[0] as X509Certificate).subjectX500Principal
|
val peerX500Principal = (peerChain[0] as X509Certificate).subjectX500Principal
|
||||||
val x500name = X500Name(peerX500Principal.name)
|
val x500name = X500Name(peerX500Principal.name)
|
||||||
assertEquals(X500Name(MEGA_CORP.name), x500name)
|
assertEquals(MEGA_CORP.name, x500name)
|
||||||
|
|
||||||
|
|
||||||
val output = DataOutputStream(clientSocket.outputStream)
|
val output = DataOutputStream(clientSocket.outputStream)
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.core.node
|
|||||||
import net.corda.core.crypto.X509Utilities
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.ServiceType
|
import net.corda.core.node.services.ServiceType
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -10,7 +11,7 @@ import kotlin.test.assertFailsWith
|
|||||||
|
|
||||||
class ServiceInfoTests {
|
class ServiceInfoTests {
|
||||||
val serviceType = ServiceType.getServiceType("test", "service").getSubType("subservice")
|
val serviceType = ServiceType.getServiceType("test", "service").getSubType("subservice")
|
||||||
val name = X500Name("CN=service.name,O=R3,OU=corda,L=London,C=UK")
|
val name = getTestX509Name("service.name")
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `type and name encodes correctly`() {
|
fun `type and name encodes correctly`() {
|
||||||
|
@ -2,12 +2,12 @@ package net.corda.core.testing
|
|||||||
|
|
||||||
import com.pholser.junit.quickcheck.generator.GenerationStatus
|
import com.pholser.junit.quickcheck.generator.GenerationStatus
|
||||||
import com.pholser.junit.quickcheck.generator.Generator
|
import com.pholser.junit.quickcheck.generator.Generator
|
||||||
import com.pholser.junit.quickcheck.generator.java.lang.StringGenerator
|
|
||||||
import com.pholser.junit.quickcheck.generator.java.util.ArrayListGenerator
|
import com.pholser.junit.quickcheck.generator.java.util.ArrayListGenerator
|
||||||
import com.pholser.junit.quickcheck.random.SourceOfRandomness
|
import com.pholser.junit.quickcheck.random.SourceOfRandomness
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
@ -51,7 +51,7 @@ class AnonymousPartyGenerator : Generator<AnonymousParty>(AnonymousParty::class.
|
|||||||
|
|
||||||
class PartyGenerator : Generator<Party>(Party::class.java) {
|
class PartyGenerator : Generator<Party>(Party::class.java) {
|
||||||
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Party {
|
override fun generate(random: SourceOfRandomness, status: GenerationStatus): Party {
|
||||||
return Party(StringGenerator().generate(random, status), PublicKeyGenerator().generate(random, status))
|
return Party(X500NameGenerator().generate(random, status), PublicKeyGenerator().generate(random, status))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +148,6 @@ class X500NameGenerator : Generator<X500Name>(X500Name::class.java) {
|
|||||||
for (word in 0..wordCount) {
|
for (word in 0..wordCount) {
|
||||||
appendProperNoun(cn, random, status).append(" ")
|
appendProperNoun(cn, random, status).append(" ")
|
||||||
}
|
}
|
||||||
return X509Utilities.getDevX509Name(cn.trim().toString())
|
return getTestX509Name(cn.trim().toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.contracts.universal
|
package net.corda.contracts.universal
|
||||||
|
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -46,7 +47,7 @@ private class PrettyPrint(arr : Arrangement) {
|
|||||||
|
|
||||||
fun createPartyName(party : Party) : String
|
fun createPartyName(party : Party) : String
|
||||||
{
|
{
|
||||||
val parts = party.name.toLowerCase().split(' ')
|
val parts = party.name.commonName.toLowerCase().split(' ')
|
||||||
|
|
||||||
var camelName = parts.drop(1).fold(parts.first()) {
|
var camelName = parts.drop(1).fold(parts.first()) {
|
||||||
s, i -> s + i.first().toUpperCase() + i.drop(1)
|
s, i -> s + i.first().toUpperCase() + i.drop(1)
|
||||||
@ -64,7 +65,7 @@ private class PrettyPrint(arr : Arrangement) {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
parties.forEach {
|
parties.forEach {
|
||||||
println( "val ${createPartyName(it)} = Party(\"${it.name}\", \"${it.owningKey}\")" )
|
println( "val ${createPartyName(it)} = Party(\"${it.name.commonName}\", \"${it.owningKey}\")" )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,20 +5,21 @@ import net.corda.nodeapi.config.SSLConfiguration
|
|||||||
import org.apache.activemq.artemis.api.core.TransportConfiguration
|
import org.apache.activemq.artemis.api.core.TransportConfiguration
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory
|
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants
|
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.nio.file.FileSystems
|
import java.nio.file.FileSystems
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
sealed class ConnectionDirection {
|
sealed class ConnectionDirection {
|
||||||
data class Inbound(val acceptorFactoryClassName: String) : ConnectionDirection()
|
data class Inbound(val acceptorFactoryClassName: String) : ConnectionDirection()
|
||||||
data class Outbound(
|
data class Outbound(
|
||||||
val expectedCommonName: String? = null,
|
val expectedCommonName: X500Name? = null,
|
||||||
val connectorFactoryClassName: String = NettyConnectorFactory::class.java.name
|
val connectorFactoryClassName: String = NettyConnectorFactory::class.java.name
|
||||||
) : ConnectionDirection()
|
) : ConnectionDirection()
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtemisTcpTransport {
|
class ArtemisTcpTransport {
|
||||||
companion object {
|
companion object {
|
||||||
const val VERIFY_PEER_COMMON_NAME = "corda.verifyPeerCommonName"
|
const val VERIFY_PEER_LEGAL_NAME = "corda.verifyPeerCommonName"
|
||||||
|
|
||||||
// Restrict enabled Cipher Suites to AES and GCM as minimum for the bulk cipher.
|
// Restrict enabled Cipher Suites to AES and GCM as minimum for the bulk cipher.
|
||||||
// Our self-generated certificates all use ECDSA for handshakes, but we allow classical RSA certificates to work
|
// Our self-generated certificates all use ECDSA for handshakes, but we allow classical RSA certificates to work
|
||||||
@ -67,7 +68,7 @@ class ArtemisTcpTransport {
|
|||||||
TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME to CIPHER_SUITES.joinToString(","),
|
TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME to CIPHER_SUITES.joinToString(","),
|
||||||
TransportConstants.ENABLED_PROTOCOLS_PROP_NAME to "TLSv1.2",
|
TransportConstants.ENABLED_PROTOCOLS_PROP_NAME to "TLSv1.2",
|
||||||
TransportConstants.NEED_CLIENT_AUTH_PROP_NAME to true,
|
TransportConstants.NEED_CLIENT_AUTH_PROP_NAME to true,
|
||||||
VERIFY_PEER_COMMON_NAME to (direction as? ConnectionDirection.Outbound)?.expectedCommonName
|
VERIFY_PEER_LEGAL_NAME to (direction as? ConnectionDirection.Outbound)?.expectedCommonName
|
||||||
)
|
)
|
||||||
options.putAll(tlsOptions)
|
options.putAll(tlsOptions)
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ private fun Config.getCollectionValue(path: String, type: KType): Collection<Any
|
|||||||
HostAndPort::class -> getStringList(path).map(HostAndPort::fromString)
|
HostAndPort::class -> getStringList(path).map(HostAndPort::fromString)
|
||||||
Path::class -> getStringList(path).map { Paths.get(it) }
|
Path::class -> getStringList(path).map { Paths.get(it) }
|
||||||
URL::class -> getStringList(path).map(::URL)
|
URL::class -> getStringList(path).map(::URL)
|
||||||
|
X500Name::class -> getStringList(path).map(::X500Name)
|
||||||
Properties::class -> getConfigList(path).map(Config::toProperties)
|
Properties::class -> getConfigList(path).map(Config::toProperties)
|
||||||
else -> if (elementClass.java.isEnum) {
|
else -> if (elementClass.java.isEnum) {
|
||||||
getStringList(path).map { parseEnum(elementClass.java, it) }
|
getStringList(path).map { parseEnum(elementClass.java, it) }
|
||||||
|
@ -6,7 +6,9 @@ import com.typesafe.config.ConfigFactory.empty
|
|||||||
import com.typesafe.config.ConfigRenderOptions.defaults
|
import com.typesafe.config.ConfigRenderOptions.defaults
|
||||||
import com.typesafe.config.ConfigValueFactory
|
import com.typesafe.config.ConfigValueFactory
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -15,6 +17,7 @@ import java.time.Instant
|
|||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.reflect.full.primaryConstructor
|
import kotlin.reflect.full.primaryConstructor
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class ConfigParsingTest {
|
class ConfigParsingTest {
|
||||||
@Test
|
@Test
|
||||||
@ -109,6 +112,11 @@ class ConfigParsingTest {
|
|||||||
assertThat(empty().parseAs<StringSetData>().values).isEmpty()
|
assertThat(empty().parseAs<StringSetData>().values).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun x500Name() {
|
||||||
|
testPropertyType<X500NameData, X500NameListData, X500Name>(getTestX509Name("Mock Node"), getTestX509Name("Mock Node 2"), valuesToString = true)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `multi property data class`() {
|
fun `multi property data class`() {
|
||||||
val data = config(
|
val data = config(
|
||||||
@ -223,6 +231,8 @@ class ConfigParsingTest {
|
|||||||
data class PathListData(override val values: List<Path>) : ListData<Path>
|
data class PathListData(override val values: List<Path>) : ListData<Path>
|
||||||
data class URLData(override val value: URL) : SingleData<URL>
|
data class URLData(override val value: URL) : SingleData<URL>
|
||||||
data class URLListData(override val values: List<URL>) : ListData<URL>
|
data class URLListData(override val values: List<URL>) : ListData<URL>
|
||||||
|
data class X500NameData(override val value: X500Name) : SingleData<X500Name>
|
||||||
|
data class X500NameListData(override val values: List<X500Name>) : ListData<X500Name>
|
||||||
data class PropertiesData(override val value: Properties) : SingleData<Properties>
|
data class PropertiesData(override val value: Properties) : SingleData<Properties>
|
||||||
data class PropertiesListData(override val values: List<Properties>) : ListData<Properties>
|
data class PropertiesListData(override val values: List<Properties>) : ListData<Properties>
|
||||||
data class MultiPropertyData(val i: Int, val b: Boolean, val l: List<String>)
|
data class MultiPropertyData(val i: Int, val b: Boolean, val l: List<String>)
|
||||||
|
@ -292,7 +292,7 @@ class VaultSchemaTest {
|
|||||||
stateStatus = Vault.StateStatus.UNCONSUMED
|
stateStatus = Vault.StateStatus.UNCONSUMED
|
||||||
contractStateClassName = state.data.javaClass.name
|
contractStateClassName = state.data.javaClass.name
|
||||||
contractState = state.serialize().bytes
|
contractState = state.serialize().bytes
|
||||||
notaryName = state.notary.name
|
notaryName = state.notary.name.toString()
|
||||||
notaryKey = state.notary.owningKey.toBase58String()
|
notaryKey = state.notary.owningKey.toBase58String()
|
||||||
recordedTime = Instant.now()
|
recordedTime = Instant.now()
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.core.contracts.StateAndRef
|
|||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.contracts.TransactionType
|
import net.corda.core.contracts.TransactionType
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
@ -19,6 +20,9 @@ import net.corda.node.services.transactions.BFTNonValidatingNotaryService
|
|||||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x500.X500NameBuilder
|
||||||
|
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -27,7 +31,19 @@ import kotlin.test.assertFailsWith
|
|||||||
|
|
||||||
class BFTNotaryServiceTests : NodeBasedTest() {
|
class BFTNotaryServiceTests : NodeBasedTest() {
|
||||||
private companion object {
|
private companion object {
|
||||||
val notaryCommonName = "BFT Notary Server"
|
val notaryCommonName = X500Name("CN=BFT Notary Server,O=R3,OU=corda,L=Zurich,C=CH")
|
||||||
|
|
||||||
|
fun buildNodeName(it: Int, notaryName: X500Name): X500Name {
|
||||||
|
val builder = X500NameBuilder()
|
||||||
|
notaryName.rdNs.map { it.first }.forEach { attr ->
|
||||||
|
if (attr.type == BCStyle.CN) {
|
||||||
|
builder.addRDN(BCStyle.CN, "${attr.value}-$it")
|
||||||
|
} else {
|
||||||
|
builder.addRDN(attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -73,13 +89,13 @@ class BFTNotaryServiceTests : NodeBasedTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startBFTNotaryCluster(notaryName: String,
|
private fun startBFTNotaryCluster(notaryName: X500Name,
|
||||||
clusterSize: Int,
|
clusterSize: Int,
|
||||||
serviceType: ServiceType): List<Node> {
|
serviceType: ServiceType): List<Node> {
|
||||||
require(clusterSize > 0)
|
require(clusterSize > 0)
|
||||||
val quorum = (2 * clusterSize + 1) / 3
|
val quorum = (2 * clusterSize + 1) / 3
|
||||||
ServiceIdentityGenerator.generateToDisk(
|
ServiceIdentityGenerator.generateToDisk(
|
||||||
(0 until clusterSize).map { tempFolder.root.toPath() / "$notaryName-$it" },
|
(0 until clusterSize).map { tempFolder.root.toPath() / "${notaryName.commonName}-$it" },
|
||||||
serviceType.id,
|
serviceType.id,
|
||||||
notaryName,
|
notaryName,
|
||||||
quorum)
|
quorum)
|
||||||
@ -87,7 +103,7 @@ class BFTNotaryServiceTests : NodeBasedTest() {
|
|||||||
val serviceInfo = ServiceInfo(serviceType, notaryName)
|
val serviceInfo = ServiceInfo(serviceType, notaryName)
|
||||||
val nodes = (0 until clusterSize).map {
|
val nodes = (0 until clusterSize).map {
|
||||||
startNode(
|
startNode(
|
||||||
"$notaryName-$it",
|
buildNodeName(it, notaryName),
|
||||||
advertisedServices = setOf(serviceInfo),
|
advertisedServices = setOf(serviceInfo),
|
||||||
configOverrides = mapOf("notaryNodeId" to it)
|
configOverrides = mapOf("notaryNodeId" to it)
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
|
@ -15,6 +15,7 @@ import net.corda.flows.NotaryFlow
|
|||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -22,7 +23,7 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
class RaftNotaryServiceTests : NodeBasedTest() {
|
class RaftNotaryServiceTests : NodeBasedTest() {
|
||||||
private val notaryName = "CN=RAFT Notary Service,O=R3,OU=corda,L=London,C=UK"
|
private val notaryName = X500Name("CN=RAFT Notary Service,O=R3,OU=corda,L=London,C=UK")
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `detect double spend`() {
|
fun `detect double spend`() {
|
||||||
|
@ -5,6 +5,8 @@ import com.google.common.util.concurrent.Futures
|
|||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
|
import net.corda.core.utilities.BOB
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
@ -14,8 +16,8 @@ class FlowVersioningTest : NodeBasedTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `core flows receive platform version of initiator`() {
|
fun `core flows receive platform version of initiator`() {
|
||||||
val (alice, bob) = Futures.allAsList(
|
val (alice, bob) = Futures.allAsList(
|
||||||
startNode("Alice", platformVersion = 2),
|
startNode(ALICE.name, platformVersion = 2),
|
||||||
startNode("Bob", platformVersion = 3)).getOrThrow()
|
startNode(BOB.name, platformVersion = 3)).getOrThrow()
|
||||||
bob.installCoreFlow(ClientFlow::class, ::SendBackPlatformVersionFlow)
|
bob.installCoreFlow(ClientFlow::class, ::SendBackPlatformVersionFlow)
|
||||||
val resultFuture = alice.services.startFlow(ClientFlow(bob.info.legalIdentity)).resultFuture
|
val resultFuture = alice.services.startFlow(ClientFlow(bob.info.legalIdentity)).resultFuture
|
||||||
assertThat(resultFuture.getOrThrow()).isEqualTo(2)
|
assertThat(resultFuture.getOrThrow()).isEqualTo(2)
|
||||||
|
@ -4,6 +4,7 @@ import com.google.common.util.concurrent.Futures
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.crypto.X509Utilities
|
import net.corda.core.crypto.X509Utilities
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.core.node.services.DEFAULT_SESSION_ID
|
import net.corda.core.node.services.DEFAULT_SESSION_ID
|
||||||
@ -18,6 +19,7 @@ import net.corda.node.services.transactions.RaftValidatingNotaryService
|
|||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||||
import net.corda.testing.freeLocalHostAndPort
|
import net.corda.testing.freeLocalHostAndPort
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import net.corda.testing.node.NodeBasedTest
|
import net.corda.testing.node.NodeBasedTest
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
@ -30,8 +32,8 @@ import java.util.concurrent.atomic.AtomicInteger
|
|||||||
|
|
||||||
class P2PMessagingTest : NodeBasedTest() {
|
class P2PMessagingTest : NodeBasedTest() {
|
||||||
private companion object {
|
private companion object {
|
||||||
val DISTRIBUTED_SERVICE_NAME = X509Utilities.getDevX509Name("DistributedService")
|
val DISTRIBUTED_SERVICE_NAME = getTestX509Name("DistributedService")
|
||||||
val SERVICE_2_NAME = X509Utilities.getDevX509Name("Service Node 2")
|
val SERVICE_2_NAME = getTestX509Name("Service Node 2")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -65,7 +67,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
|
|
||||||
val root = tempFolder.root.toPath()
|
val root = tempFolder.root.toPath()
|
||||||
ServiceIdentityGenerator.generateToDisk(
|
ServiceIdentityGenerator.generateToDisk(
|
||||||
listOf(root / DUMMY_MAP.name.toString(), root / SERVICE_2_NAME.toString()),
|
listOf(root / DUMMY_MAP.name.commonName, root / SERVICE_2_NAME.commonName),
|
||||||
RaftValidatingNotaryService.type.id,
|
RaftValidatingNotaryService.type.id,
|
||||||
DISTRIBUTED_SERVICE_NAME)
|
DISTRIBUTED_SERVICE_NAME)
|
||||||
|
|
||||||
@ -96,7 +98,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `distributed service requests are retried if one of the nodes in the cluster goes down without sending a response`() {
|
fun `distributed service requests are retried if one of the nodes in the cluster goes down without sending a response`() {
|
||||||
val distributedServiceNodes = startNotaryCluster("DistributedService", 2).getOrThrow()
|
val distributedServiceNodes = startNotaryCluster(DISTRIBUTED_SERVICE_NAME, 2).getOrThrow()
|
||||||
val alice = startNode(ALICE.name, configOverrides = mapOf("messageRedeliveryDelaySeconds" to 1)).getOrThrow()
|
val alice = startNode(ALICE.name, configOverrides = mapOf("messageRedeliveryDelaySeconds" to 1)).getOrThrow()
|
||||||
val serviceAddress = alice.services.networkMapCache.run {
|
val serviceAddress = alice.services.networkMapCache.run {
|
||||||
alice.net.getAddressOfParty(getPartyInfo(getAnyNotary()!!)!!)
|
alice.net.getAddressOfParty(getPartyInfo(getAnyNotary()!!)!!)
|
||||||
@ -121,7 +123,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `distributed service request retries are persisted across client node restarts`() {
|
fun `distributed service request retries are persisted across client node restarts`() {
|
||||||
val distributedServiceNodes = startNotaryCluster("DistributedService", 2).getOrThrow()
|
val distributedServiceNodes = startNotaryCluster(DISTRIBUTED_SERVICE_NAME, 2).getOrThrow()
|
||||||
val alice = startNode(ALICE.name, configOverrides = mapOf("messageRedeliveryDelaySeconds" to 1)).getOrThrow()
|
val alice = startNode(ALICE.name, configOverrides = mapOf("messageRedeliveryDelaySeconds" to 1)).getOrThrow()
|
||||||
val serviceAddress = alice.services.networkMapCache.run {
|
val serviceAddress = alice.services.networkMapCache.run {
|
||||||
alice.net.getAddressOfParty(getPartyInfo(getAnyNotary()!!)!!)
|
alice.net.getAddressOfParty(getPartyInfo(getAnyNotary()!!)!!)
|
||||||
@ -194,7 +196,7 @@ class P2PMessagingTest : NodeBasedTest() {
|
|||||||
node.respondWith(node.info)
|
node.respondWith(node.info)
|
||||||
}
|
}
|
||||||
val serviceAddress = originatingNode.services.networkMapCache.run {
|
val serviceAddress = originatingNode.services.networkMapCache.run {
|
||||||
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName.toString())!!)!!)
|
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName)!!)!!)
|
||||||
}
|
}
|
||||||
val participatingNodes = HashSet<Any>()
|
val participatingNodes = HashSet<Any>()
|
||||||
// Try several times so that we can be fairly sure that any node not participating is not due to Artemis' selection
|
// Try several times so that we can be fairly sure that any node not participating is not due to Artemis' selection
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.services.messaging
|
|||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.crypto.commonName
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
@ -33,22 +34,22 @@ class P2PSecurityTest : NodeBasedTest() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `incorrect legal name for the network map service config`() {
|
fun `incorrect legal name for the network map service config`() {
|
||||||
val incorrectNetworkMapName = random63BitValue().toString()
|
val incorrectNetworkMapName = X509Utilities.getDevX509Name(random63BitValue().toString())
|
||||||
val node = startNode(BOB.name, configOverrides = mapOf(
|
val node = startNode(BOB.name, configOverrides = mapOf(
|
||||||
"networkMapService" to mapOf(
|
"networkMapService" to mapOf(
|
||||||
"address" to networkMapNode.configuration.p2pAddress.toString(),
|
"address" to networkMapNode.configuration.p2pAddress.toString(),
|
||||||
"legalName" to incorrectNetworkMapName
|
"legalName" to incorrectNetworkMapName.toString()
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
// The connection will be rejected as the legal name doesn't match
|
// The connection will be rejected as the legal name doesn't match
|
||||||
assertThatThrownBy { node.getOrThrow() }.hasMessageContaining(incorrectNetworkMapName)
|
assertThatThrownBy { node.getOrThrow() }.hasMessageContaining(incorrectNetworkMapName.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `register with the network map service using a legal name different from the TLS CN`() {
|
fun `register with the network map service using a legal name different from the TLS CN`() {
|
||||||
startSimpleNode(X500Name(DUMMY_BANK_A.name)).use {
|
startSimpleNode(DUMMY_BANK_A.name).use {
|
||||||
// Register with the network map using a different legal name
|
// Register with the network map using a different legal name
|
||||||
val response = it.registerWithNetworkMap(X500Name(DUMMY_BANK_B.name))
|
val response = it.registerWithNetworkMap(DUMMY_BANK_B.name)
|
||||||
// We don't expect a response because the network map's host verification will prevent a connection back
|
// We don't expect a response because the network map's host verification will prevent a connection back
|
||||||
// to the attacker as the TLS CN will not match the legal name it has just provided
|
// to the attacker as the TLS CN will not match the legal name it has just provided
|
||||||
assertThatExceptionOfType(TimeoutException::class.java).isThrownBy {
|
assertThatExceptionOfType(TimeoutException::class.java).isThrownBy {
|
||||||
|
@ -63,23 +63,6 @@ private val log: Logger = loggerFor<DriverDSL>()
|
|||||||
* This is the interface that's exposed to DSL users.
|
* This is the interface that's exposed to DSL users.
|
||||||
*/
|
*/
|
||||||
interface DriverDSLExposedInterface {
|
interface DriverDSLExposedInterface {
|
||||||
/**
|
|
||||||
* Starts a [net.corda.node.internal.Node] in a separate process.
|
|
||||||
*
|
|
||||||
* @param providedName Name of the node, which will be its legal name in [Party].
|
|
||||||
* Note that this must be unique as the driver uses it as a primary key!
|
|
||||||
* @param advertisedServices The set of services to be advertised by the node. Defaults to empty set.
|
|
||||||
* @param verifierType The type of transaction verifier to use. See: [VerifierType]
|
|
||||||
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to empty list.
|
|
||||||
* @return The [NodeInfo] of the started up node retrieved from the network map service.
|
|
||||||
*/
|
|
||||||
@Deprecated("To be removed once X500Name is used as legal name everywhere")
|
|
||||||
fun startNode(providedName: String?,
|
|
||||||
advertisedServices: Set<ServiceInfo> = emptySet(),
|
|
||||||
rpcUsers: List<User> = emptyList(),
|
|
||||||
verifierType: VerifierType = VerifierType.InMemory,
|
|
||||||
customOverrides: Map<String, Any?> = emptyMap()): ListenableFuture<NodeHandle>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a [net.corda.node.internal.Node] in a separate process.
|
* Starts a [net.corda.node.internal.Node] in a separate process.
|
||||||
*
|
*
|
||||||
@ -107,7 +90,7 @@ interface DriverDSLExposedInterface {
|
|||||||
* @return The [Party] identity of the distributed notary service, and the [NodeInfo]s of the notaries in the cluster.
|
* @return The [Party] identity of the distributed notary service, and the [NodeInfo]s of the notaries in the cluster.
|
||||||
*/
|
*/
|
||||||
fun startNotaryCluster(
|
fun startNotaryCluster(
|
||||||
notaryName: String,
|
notaryName: X500Name,
|
||||||
clusterSize: Int = 3,
|
clusterSize: Int = 3,
|
||||||
type: ServiceType = RaftValidatingNotaryService.type,
|
type: ServiceType = RaftValidatingNotaryService.type,
|
||||||
verifierType: VerifierType = VerifierType.InMemory,
|
verifierType: VerifierType = VerifierType.InMemory,
|
||||||
@ -444,25 +427,13 @@ class DriverDSL(
|
|||||||
verifierType: VerifierType,
|
verifierType: VerifierType,
|
||||||
customOverrides: Map<String, Any?>
|
customOverrides: Map<String, Any?>
|
||||||
): ListenableFuture<NodeHandle> {
|
): ListenableFuture<NodeHandle> {
|
||||||
return startNode(providedName?.toString(), advertisedServices, rpcUsers, verifierType, customOverrides)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun startNode(providedName: String?,
|
|
||||||
advertisedServices: Set<ServiceInfo>,
|
|
||||||
rpcUsers: List<User>,
|
|
||||||
verifierType: VerifierType,
|
|
||||||
customOverrides: Map<String, Any?>): ListenableFuture<NodeHandle> {
|
|
||||||
val p2pAddress = portAllocation.nextHostAndPort()
|
val p2pAddress = portAllocation.nextHostAndPort()
|
||||||
val rpcAddress = portAllocation.nextHostAndPort()
|
val rpcAddress = portAllocation.nextHostAndPort()
|
||||||
val webAddress = portAllocation.nextHostAndPort()
|
val webAddress = portAllocation.nextHostAndPort()
|
||||||
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
||||||
val name = providedName.toString() ?: X509Utilities.getDevX509Name("${pickA(name).commonName}-${p2pAddress.port}").toString()
|
// TODO: Derive name from the full picked name, don't just wrap the common name
|
||||||
val commonName = try {
|
val name = providedName ?: X509Utilities.getDevX509Name("${pickA(name).commonName}-${p2pAddress.port}")
|
||||||
X500Name(name).commonName
|
val baseDirectory = driverDirectory / name.commonName
|
||||||
} catch(ex: IllegalArgumentException) {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
val baseDirectory = driverDirectory / commonName
|
|
||||||
val configOverrides = mapOf(
|
val configOverrides = mapOf(
|
||||||
"myLegalName" to name.toString(),
|
"myLegalName" to name.toString(),
|
||||||
"p2pAddress" to p2pAddress.toString(),
|
"p2pAddress" to p2pAddress.toString(),
|
||||||
@ -471,7 +442,7 @@ class DriverDSL(
|
|||||||
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
|
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
|
||||||
"networkMapService" to mapOf(
|
"networkMapService" to mapOf(
|
||||||
"address" to networkMapAddress.toString(),
|
"address" to networkMapAddress.toString(),
|
||||||
"legalName" to networkMapLegalName
|
"legalName" to networkMapLegalName.toString()
|
||||||
),
|
),
|
||||||
"useTestClock" to useTestClock,
|
"useTestClock" to useTestClock,
|
||||||
"rpcUsers" to rpcUsers.map {
|
"rpcUsers" to rpcUsers.map {
|
||||||
@ -503,14 +474,23 @@ class DriverDSL(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun startNotaryCluster(
|
override fun startNotaryCluster(
|
||||||
notaryName: String,
|
notaryName: X500Name,
|
||||||
clusterSize: Int,
|
clusterSize: Int,
|
||||||
type: ServiceType,
|
type: ServiceType,
|
||||||
verifierType: VerifierType,
|
verifierType: VerifierType,
|
||||||
rpcUsers: List<User>
|
rpcUsers: List<User>
|
||||||
): ListenableFuture<Pair<Party, List<NodeHandle>>> {
|
): ListenableFuture<Pair<Party, List<NodeHandle>>> {
|
||||||
val nodeNames = (1..clusterSize).map { "Notary Node $it" }
|
val nodeNames = (1..clusterSize).map {
|
||||||
val paths = nodeNames.map { driverDirectory / it }
|
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
||||||
|
nameBuilder.addRDN(BCStyle.CN, "${DUMMY_NOTARY.name.commonName} $it")
|
||||||
|
DUMMY_NOTARY.name.rdNs.forEach { rdn ->
|
||||||
|
if (rdn.first.type != BCStyle.CN) {
|
||||||
|
nameBuilder.addRDN(rdn.first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nameBuilder.build()
|
||||||
|
}
|
||||||
|
val paths = nodeNames.map { driverDirectory / it.commonName }
|
||||||
ServiceIdentityGenerator.generateToDisk(paths, type.id, notaryName)
|
ServiceIdentityGenerator.generateToDisk(paths, type.id, notaryName)
|
||||||
|
|
||||||
val serviceInfo = ServiceInfo(type, notaryName)
|
val serviceInfo = ServiceInfo(type, notaryName)
|
||||||
@ -567,17 +547,12 @@ class DriverDSL(
|
|||||||
override fun startNetworkMapService() {
|
override fun startNetworkMapService() {
|
||||||
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
||||||
val apiAddress = portAllocation.nextHostAndPort().toString()
|
val apiAddress = portAllocation.nextHostAndPort().toString()
|
||||||
val nodeDirectoryName = try {
|
val baseDirectory = driverDirectory / networkMapLegalName.commonName
|
||||||
X500Name(networkMapLegalName).commonName
|
|
||||||
} catch(ex: IllegalArgumentException) {
|
|
||||||
networkMapLegalName
|
|
||||||
}
|
|
||||||
val baseDirectory = driverDirectory / nodeDirectoryName
|
|
||||||
val config = ConfigHelper.loadConfig(
|
val config = ConfigHelper.loadConfig(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
allowMissingConfig = true,
|
allowMissingConfig = true,
|
||||||
configOverrides = mapOf(
|
configOverrides = mapOf(
|
||||||
"myLegalName" to networkMapLegalName,
|
"myLegalName" to networkMapLegalName.toString(),
|
||||||
// TODO: remove the webAddress as NMS doesn't need to run a web server. This will cause all
|
// TODO: remove the webAddress as NMS doesn't need to run a web server. This will cause all
|
||||||
// node port numbers to be shifted, so all demos and docs need to be updated accordingly.
|
// node port numbers to be shifted, so all demos and docs need to be updated accordingly.
|
||||||
"webAddress" to apiAddress,
|
"webAddress" to apiAddress,
|
||||||
@ -593,9 +568,9 @@ class DriverDSL(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val name = arrayOf(
|
val name = arrayOf(
|
||||||
X500Name(ALICE.name),
|
ALICE.name,
|
||||||
X500Name(BOB.name),
|
BOB.name,
|
||||||
X500Name(DUMMY_BANK_A.name)
|
DUMMY_BANK_A.name
|
||||||
)
|
)
|
||||||
|
|
||||||
fun <A> pickA(array: Array<A>): A = array[Math.abs(Random().nextInt()) % array.size]
|
fun <A> pickA(array: Array<A>): A = array[Math.abs(Random().nextInt()) % array.size]
|
||||||
|
@ -58,6 +58,7 @@ import net.corda.node.utilities.AffinityExecutor
|
|||||||
import net.corda.node.utilities.configureDatabase
|
import net.corda.node.utilities.configureDatabase
|
||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -338,7 +339,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
protected open fun makeServiceEntries(): List<ServiceEntry> {
|
protected open fun makeServiceEntries(): List<ServiceEntry> {
|
||||||
return advertisedServices.map {
|
return advertisedServices.map {
|
||||||
val serviceId = it.type.id
|
val serviceId = it.type.id
|
||||||
val serviceName = it.name ?: "ou=$serviceId,${configuration.myLegalName}"
|
val serviceName = it.name ?: X500Name("CN=$serviceId,${configuration.myLegalName}")
|
||||||
val identity = obtainKeyPair(configuration.baseDirectory, serviceId + "-private-key", serviceId + "-public", serviceName).first
|
val identity = obtainKeyPair(configuration.baseDirectory, serviceId + "-private-key", serviceId + "-public", serviceName).first
|
||||||
ServiceEntry(it, identity)
|
ServiceEntry(it, identity)
|
||||||
}
|
}
|
||||||
@ -558,7 +559,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
protected fun obtainLegalIdentity(): Party = obtainKeyPair(configuration.baseDirectory, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).first
|
protected fun obtainLegalIdentity(): Party = obtainKeyPair(configuration.baseDirectory, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).first
|
||||||
protected fun obtainLegalIdentityKey(): KeyPair = obtainKeyPair(configuration.baseDirectory, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).second
|
protected fun obtainLegalIdentityKey(): KeyPair = obtainKeyPair(configuration.baseDirectory, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).second
|
||||||
|
|
||||||
private fun obtainKeyPair(dir: Path, privateKeyFileName: String, publicKeyFileName: String, serviceName: String? = null): Pair<Party, KeyPair> {
|
private fun obtainKeyPair(dir: Path, privateKeyFileName: String, publicKeyFileName: String, serviceName: X500Name? = null): Pair<Party, KeyPair> {
|
||||||
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that
|
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that
|
||||||
// is distributed to other peers and we use it (or a key signed by it) when we need to do something
|
// is distributed to other peers and we use it (or a key signed by it) when we need to do something
|
||||||
// "permissioned". The identity file is what gets distributed and contains the node's legal name along with
|
// "permissioned". The identity file is what gets distributed and contains the node's legal name along with
|
||||||
@ -566,13 +567,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
// the legal name is actually validated in some way.
|
// the legal name is actually validated in some way.
|
||||||
val privKeyFile = dir / privateKeyFileName
|
val privKeyFile = dir / privateKeyFileName
|
||||||
val pubIdentityFile = dir / publicKeyFileName
|
val pubIdentityFile = dir / publicKeyFileName
|
||||||
val identityName = serviceName ?: configuration.myLegalName.toString()
|
val identityPrincipal: X500Name = serviceName ?: configuration.myLegalName
|
||||||
|
|
||||||
val identityAndKey = if (!privKeyFile.exists()) {
|
val identityAndKey = if (!privKeyFile.exists()) {
|
||||||
log.info("Identity key not found, generating fresh key!")
|
log.info("Identity key not found, generating fresh key!")
|
||||||
val keyPair: KeyPair = generateKeyPair()
|
val keyPair: KeyPair = generateKeyPair()
|
||||||
keyPair.serialize().writeToFile(privKeyFile)
|
keyPair.serialize().writeToFile(privKeyFile)
|
||||||
val myIdentity = Party(identityName, keyPair.public)
|
val myIdentity = Party(identityPrincipal, keyPair.public)
|
||||||
// We include the Party class with the file here to help catch mixups when admins provide files of the
|
// We include the Party class with the file here to help catch mixups when admins provide files of the
|
||||||
// wrong type by mistake.
|
// wrong type by mistake.
|
||||||
myIdentity.serialize().writeToFile(pubIdentityFile)
|
myIdentity.serialize().writeToFile(pubIdentityFile)
|
||||||
@ -582,9 +583,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
// This is just a sanity check. It shouldn't fail unless the admin has fiddled with the files and messed
|
// This is just a sanity check. It shouldn't fail unless the admin has fiddled with the files and messed
|
||||||
// things up for us.
|
// things up for us.
|
||||||
val myIdentity = pubIdentityFile.readAll().deserialize<Party>()
|
val myIdentity = pubIdentityFile.readAll().deserialize<Party>()
|
||||||
if (myIdentity.name != identityName)
|
if (myIdentity.name != identityPrincipal)
|
||||||
throw ConfigurationException("The legal name in the config file doesn't match the stored identity file:" +
|
throw ConfigurationException("The legal name in the config file doesn't match the stored identity file:" +
|
||||||
"$identityName vs ${myIdentity.name}")
|
"$identityPrincipal vs ${myIdentity.name}")
|
||||||
// Load the private key.
|
// Load the private key.
|
||||||
val keyPair = privKeyFile.readAll().deserialize<KeyPair>()
|
val keyPair = privKeyFile.readAll().deserialize<KeyPair>()
|
||||||
Pair(myIdentity, keyPair)
|
Pair(myIdentity, keyPair)
|
||||||
|
@ -173,6 +173,7 @@ class CordaRPCOpsImpl(
|
|||||||
|
|
||||||
override fun waitUntilRegisteredWithNetworkMap() = services.networkMapCache.mapServiceRegistered
|
override fun waitUntilRegisteredWithNetworkMap() = services.networkMapCache.mapServiceRegistered
|
||||||
override fun partyFromKey(key: PublicKey) = services.identityService.partyFromKey(key)
|
override fun partyFromKey(key: PublicKey) = services.identityService.partyFromKey(key)
|
||||||
|
@Deprecated("Use partyFromX500Name instead")
|
||||||
override fun partyFromName(name: String) = services.identityService.partyFromName(name)
|
override fun partyFromName(name: String) = services.identityService.partyFromName(name)
|
||||||
override fun partyFromX500Name(x500Name: X500Name)= services.identityService.partyFromX500Name(x500Name)
|
override fun partyFromX500Name(x500Name: X500Name)= services.identityService.partyFromX500Name(x500Name)
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import net.corda.node.services.transactions.RaftValidatingNotaryService
|
|||||||
import net.corda.node.utilities.AddressUtils
|
import net.corda.node.utilities.AddressUtils
|
||||||
import net.corda.node.utilities.AffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor
|
||||||
import net.corda.nodeapi.ArtemisMessagingComponent.NetworkMapAddress
|
import net.corda.nodeapi.ArtemisMessagingComponent.NetworkMapAddress
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.io.RandomAccessFile
|
import java.io.RandomAccessFile
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
@ -317,4 +318,4 @@ class Node(override val configuration: FullNodeConfiguration,
|
|||||||
|
|
||||||
class ConfigurationException(message: String) : Exception(message)
|
class ConfigurationException(message: String) : Exception(message)
|
||||||
|
|
||||||
data class NetworkMapInfo(val address: HostAndPort, val legalName: String)
|
data class NetworkMapInfo(val address: HostAndPort, val legalName: X500Name)
|
||||||
|
@ -7,8 +7,8 @@ import net.corda.core.node.services.IdentityService
|
|||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.core.utilities.trace
|
import net.corda.core.utilities.trace
|
||||||
import java.security.PublicKey
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import java.security.PublicKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import javax.annotation.concurrent.ThreadSafe
|
import javax.annotation.concurrent.ThreadSafe
|
||||||
@ -23,20 +23,21 @@ class InMemoryIdentityService : SingletonSerializeAsToken(), IdentityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val keyToParties = ConcurrentHashMap<PublicKey, Party>()
|
private val keyToParties = ConcurrentHashMap<PublicKey, Party>()
|
||||||
private val nameToParties = ConcurrentHashMap<String, Party>()
|
private val principalToParties = ConcurrentHashMap<X500Name, Party>()
|
||||||
|
|
||||||
override fun registerIdentity(party: Party) {
|
override fun registerIdentity(party: Party) {
|
||||||
log.trace { "Registering identity $party" }
|
log.trace { "Registering identity $party" }
|
||||||
keyToParties[party.owningKey] = party
|
keyToParties[party.owningKey] = party
|
||||||
nameToParties[party.name] = party
|
principalToParties[party.name] = party
|
||||||
}
|
}
|
||||||
|
|
||||||
// We give the caller a copy of the data set to avoid any locking problems
|
// We give the caller a copy of the data set to avoid any locking problems
|
||||||
override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values)
|
override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values)
|
||||||
|
|
||||||
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
|
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
|
||||||
override fun partyFromName(name: String): Party? = nameToParties[name]
|
@Deprecated("Use partyFromX500Name")
|
||||||
override fun partyFromX500Name(principal: X500Name): Party? = nameToParties[principal.toString()]
|
override fun partyFromName(name: String): Party? = principalToParties[X500Name(name)]
|
||||||
|
override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]
|
||||||
override fun partyFromAnonymous(party: AnonymousParty): Party? = partyFromKey(party.owningKey)
|
override fun partyFromAnonymous(party: AnonymousParty): Party? = partyFromKey(party.owningKey)
|
||||||
override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
|
override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
.loadCertificateFromKeyStore(config.keyStoreFile, config.keyStorePassword, CORDA_CLIENT_CA)
|
.loadCertificateFromKeyStore(config.keyStoreFile, config.keyStorePassword, CORDA_CLIENT_CA)
|
||||||
val ourSubjectDN = X500Name(ourCertificate.subjectDN.name)
|
val ourSubjectDN = X500Name(ourCertificate.subjectDN.name)
|
||||||
// This is a sanity check and should not fail unless things have been misconfigured
|
// This is a sanity check and should not fail unless things have been misconfigured
|
||||||
require(ourSubjectDN.commonName == config.myLegalName.commonName) {
|
require(ourSubjectDN == config.myLegalName) {
|
||||||
"Legal name does not match with our subject CN: $ourSubjectDN"
|
"Legal name does not match with our subject CN: $ourSubjectDN"
|
||||||
}
|
}
|
||||||
val defaultCertPolicies = mapOf(
|
val defaultCertPolicies = mapOf(
|
||||||
@ -346,7 +346,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun deployBridge(address: ArtemisPeerAddress, legalName: String) {
|
private fun deployBridge(address: ArtemisPeerAddress, legalName: X500Name) {
|
||||||
deployBridge(address.queueName, address.hostAndPort, legalName)
|
deployBridge(address.queueName, address.hostAndPort, legalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,7 +359,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
* as defined by ArtemisAddress.queueName. A bridge is then created to forward messages from this queue to the node's
|
* as defined by ArtemisAddress.queueName. A bridge is then created to forward messages from this queue to the node's
|
||||||
* P2P address.
|
* P2P address.
|
||||||
*/
|
*/
|
||||||
private fun deployBridge(queueName: String, target: HostAndPort, legalName: String) {
|
private fun deployBridge(queueName: String, target: HostAndPort, legalName: X500Name) {
|
||||||
val connectionDirection = ConnectionDirection.Outbound(
|
val connectionDirection = ConnectionDirection.Outbound(
|
||||||
connectorFactoryClassName = VerifyingNettyConnectorFactory::class.java.name,
|
connectorFactoryClassName = VerifyingNettyConnectorFactory::class.java.name,
|
||||||
expectedCommonName = legalName
|
expectedCommonName = legalName
|
||||||
@ -401,7 +401,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
internal fun hostVerificationFail(peerLegalName: X500Name, expectedLegalName: X500Name) {
|
internal fun hostVerificationFail(peerLegalName: X500Name, expectedLegalName: X500Name) {
|
||||||
log.error("Peer has wrong CN - expected $expectedLegalName but got $peerLegalName. This is either a fatal " +
|
log.error("Peer has wrong CN - expected $expectedLegalName but got $peerLegalName. This is either a fatal " +
|
||||||
"misconfiguration by the remote peer or an SSL man-in-the-middle attack!")
|
"misconfiguration by the remote peer or an SSL man-in-the-middle attack!")
|
||||||
if (expectedLegalName.toString() == config.networkMapService?.legalName) {
|
if (expectedLegalName == config.networkMapService?.legalName) {
|
||||||
// If the peer that failed host verification was the network map node then we're in big trouble and need to bail!
|
// If the peer that failed host verification was the network map node then we're in big trouble and need to bail!
|
||||||
_networkMapConnectionFuture!!.setException(IOException("${config.networkMapService} failed host verification check"))
|
_networkMapConnectionFuture!!.setException(IOException("${config.networkMapService} failed host verification check"))
|
||||||
}
|
}
|
||||||
@ -409,7 +409,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
|
|
||||||
// This is called on one of Artemis' background threads
|
// This is called on one of Artemis' background threads
|
||||||
internal fun onTcpConnection(peerLegalName: X500Name) {
|
internal fun onTcpConnection(peerLegalName: X500Name) {
|
||||||
if (peerLegalName.toString() == config.networkMapService?.legalName) {
|
if (peerLegalName == config.networkMapService?.legalName) {
|
||||||
_networkMapConnectionFuture!!.set(Unit)
|
_networkMapConnectionFuture!!.set(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,14 +437,12 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
|||||||
protocolManager: ClientProtocolManager?) :
|
protocolManager: ClientProtocolManager?) :
|
||||||
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
|
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
|
||||||
private val server = configuration?.get(ArtemisMessagingServer::class.java.name) as? ArtemisMessagingServer
|
private val server = configuration?.get(ArtemisMessagingServer::class.java.name) as? ArtemisMessagingServer
|
||||||
private val expectedCommonName = (configuration?.get(ArtemisTcpTransport.VERIFY_PEER_COMMON_NAME) as? String)?.let {
|
private val expecteLegalName: X500Name? = configuration?.get(ArtemisTcpTransport.VERIFY_PEER_LEGAL_NAME) as X500Name?
|
||||||
X500Name(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createConnection(): Connection? {
|
override fun createConnection(): Connection? {
|
||||||
val connection = super.createConnection() as NettyConnection?
|
val connection = super.createConnection() as NettyConnection?
|
||||||
if (connection != null && expectedCommonName != null) {
|
if (connection != null && expecteLegalName != null) {
|
||||||
val peerLegalName = connection
|
val peerLegalName: X500Name = connection
|
||||||
.channel
|
.channel
|
||||||
.pipeline()
|
.pipeline()
|
||||||
.get(SslHandler::class.java)
|
.get(SslHandler::class.java)
|
||||||
@ -453,10 +451,9 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
|||||||
.peerPrincipal
|
.peerPrincipal
|
||||||
.name
|
.name
|
||||||
.let(::X500Name)
|
.let(::X500Name)
|
||||||
// TODO Verify on the entire principle (subject)
|
if (peerLegalName != expecteLegalName) {
|
||||||
if (peerLegalName.commonName != expectedCommonName.commonName) {
|
|
||||||
connection.close()
|
connection.close()
|
||||||
server!!.hostVerificationFail(peerLegalName, expectedCommonName)
|
server!!.hostVerificationFail(peerLegalName, expecteLegalName)
|
||||||
return null // Artemis will keep trying to reconnect until it's told otherwise
|
return null // Artemis will keep trying to reconnect until it's told otherwise
|
||||||
} else {
|
} else {
|
||||||
server!!.onTcpConnection(peerLegalName)
|
server!!.onTcpConnection(peerLegalName)
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.core.crypto.Party
|
|||||||
import net.corda.core.messaging.SingleMessageRecipient
|
import net.corda.core.messaging.SingleMessageRecipient
|
||||||
import net.corda.node.services.api.ServiceHubInternal
|
import net.corda.node.services.api.ServiceHubInternal
|
||||||
import net.corda.node.utilities.*
|
import net.corda.node.utilities.*
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
import org.jetbrains.exposed.sql.statements.InsertStatement
|
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||||
import java.util.Collections.synchronizedMap
|
import java.util.Collections.synchronizedMap
|
||||||
@ -26,12 +27,13 @@ class PersistentNetworkMapService(services: ServiceHubInternal, minimumPlatformV
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = synchronizedMap(object : AbstractJDBCHashMap<Party, NodeRegistrationInfo, Table>(Table, loadOnInit = true) {
|
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = synchronizedMap(object : AbstractJDBCHashMap<Party, NodeRegistrationInfo, Table>(Table, loadOnInit = true) {
|
||||||
override fun keyFromRow(row: ResultRow): Party = Party(row[table.nodeParty.name], row[table.nodeParty.owningKey])
|
// TODO: We should understand an X500Name database field type, rather than manually doing the conversion ourselves
|
||||||
|
override fun keyFromRow(row: ResultRow): Party = Party(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey])
|
||||||
|
|
||||||
override fun valueFromRow(row: ResultRow): NodeRegistrationInfo = deserializeFromBlob(row[table.registrationInfo])
|
override fun valueFromRow(row: ResultRow): NodeRegistrationInfo = deserializeFromBlob(row[table.registrationInfo])
|
||||||
|
|
||||||
override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry<Party, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
|
override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry<Party, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
|
||||||
insert[table.nodeParty.name] = entry.key.name
|
insert[table.nodeParty.name] = entry.key.name.toString()
|
||||||
insert[table.nodeParty.owningKey] = entry.key.owningKey
|
insert[table.nodeParty.owningKey] = entry.key.owningKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,8 +281,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
|
|||||||
|
|
||||||
private fun onSessionMessage(message: ReceivedMessage) {
|
private fun onSessionMessage(message: ReceivedMessage) {
|
||||||
val sessionMessage = message.data.deserialize<SessionMessage>()
|
val sessionMessage = message.data.deserialize<SessionMessage>()
|
||||||
// TODO Look up the party with the full X.500 name instead of just the legal name
|
val sender = serviceHub.networkMapCache.getNodeByLegalName(message.peer)?.legalIdentity
|
||||||
val sender = serviceHub.networkMapCache.getNodeByLegalName(message.peer.commonName)?.legalIdentity
|
|
||||||
if (sender != null) {
|
if (sender != null) {
|
||||||
when (sessionMessage) {
|
when (sessionMessage) {
|
||||||
is ExistingSessionMessage -> onExistingSessionMessage(sessionMessage, sender)
|
is ExistingSessionMessage -> onExistingSessionMessage(sessionMessage, sender)
|
||||||
|
@ -54,7 +54,7 @@ class PersistentUniquenessProvider : UniquenessProvider, SingletonSerializeAsTok
|
|||||||
finalizables: MutableList<() -> Unit>) {
|
finalizables: MutableList<() -> Unit>) {
|
||||||
insert[table.consumingTxHash] = entry.value.id
|
insert[table.consumingTxHash] = entry.value.id
|
||||||
insert[table.consumingIndex] = entry.value.inputIndex
|
insert[table.consumingIndex] = entry.value.inputIndex
|
||||||
insert[table.requestingParty.name] = entry.value.requestingParty.name
|
insert[table.requestingParty.name] = entry.value.requestingParty.name.toString()
|
||||||
insert[table.requestingParty.owningKey] = entry.value.requestingParty.owningKey
|
insert[table.requestingParty.owningKey] = entry.value.requestingParty.owningKey
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -91,7 +91,7 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P
|
|||||||
stateStatus = Vault.StateStatus.UNCONSUMED
|
stateStatus = Vault.StateStatus.UNCONSUMED
|
||||||
contractStateClassName = it.value.state.data.javaClass.name
|
contractStateClassName = it.value.state.data.javaClass.name
|
||||||
contractState = it.value.state.serialize(storageKryo()).bytes
|
contractState = it.value.state.serialize(storageKryo()).bytes
|
||||||
notaryName = it.value.state.notary.name
|
notaryName = it.value.state.notary.name.toString()
|
||||||
notaryKey = it.value.state.notary.owningKey.toBase58String()
|
notaryKey = it.value.state.notary.owningKey.toBase58String()
|
||||||
recordedTime = services.clock.instant()
|
recordedTime = services.clock.instant()
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.generateKeyPair
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.core.utilities.trace
|
import net.corda.core.utilities.trace
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
@ -23,7 +24,7 @@ object ServiceIdentityGenerator {
|
|||||||
* @param serviceName The legal name of the distributed service.
|
* @param serviceName The legal name of the distributed service.
|
||||||
* @param threshold The threshold for the generated group [CompositeKey].
|
* @param threshold The threshold for the generated group [CompositeKey].
|
||||||
*/
|
*/
|
||||||
fun generateToDisk(dirs: List<Path>, serviceId: String, serviceName: String, threshold: Int = 1) {
|
fun generateToDisk(dirs: List<Path>, serviceId: String, serviceName: X500Name, threshold: Int = 1) {
|
||||||
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
|
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
|
||||||
|
|
||||||
val keyPairs = (1..dirs.size).map { generateKeyPair() }
|
val keyPairs = (1..dirs.size).map { generateKeyPair() }
|
||||||
@ -43,7 +44,7 @@ object ServiceIdentityGenerator {
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val dirs = args[0].split("|").map { Paths.get(it) }
|
val dirs = args[0].split("|").map { Paths.get(it) }
|
||||||
val serviceId = args[1]
|
val serviceId = args[1]
|
||||||
val serviceName = args[2]
|
val serviceName = X500Name(args[2])
|
||||||
val quorumSize = args.getOrNull(3)?.toInt() ?: 1
|
val quorumSize = args.getOrNull(3)?.toInt() ?: 1
|
||||||
|
|
||||||
println("Generating service identity for \"$serviceName\"")
|
println("Generating service identity for \"$serviceName\"")
|
||||||
|
@ -12,6 +12,7 @@ import net.corda.core.serialization.*;
|
|||||||
import net.corda.core.transactions.*;
|
import net.corda.core.transactions.*;
|
||||||
import net.corda.node.services.vault.schemas.*;
|
import net.corda.node.services.vault.schemas.*;
|
||||||
import net.corda.testing.node.*;
|
import net.corda.testing.node.*;
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
import org.jetbrains.annotations.*;
|
import org.jetbrains.annotations.*;
|
||||||
import org.jetbrains.exposed.sql.*;
|
import org.jetbrains.exposed.sql.*;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
@ -129,7 +130,7 @@ public class VaultQueryJavaTests {
|
|||||||
QueryCriteria vaultCriteria = new VaultQueryCriteria(status, null, contractStateTypes);
|
QueryCriteria vaultCriteria = new VaultQueryCriteria(status, null, contractStateTypes);
|
||||||
|
|
||||||
List<UniqueIdentifier> linearIds = Arrays.asList(uid);
|
List<UniqueIdentifier> linearIds = Arrays.asList(uid);
|
||||||
List<String> dealPartyNames = Arrays.asList(getMEGA_CORP().getName());
|
List<X500Name> dealPartyNames = Arrays.asList(getMEGA_CORP().getName());
|
||||||
QueryCriteria dealCriteriaAll = new LinearStateQueryCriteria(linearIds, false, dealIds, dealPartyNames);
|
QueryCriteria dealCriteriaAll = new LinearStateQueryCriteria(linearIds, false, dealIds, dealPartyNames);
|
||||||
|
|
||||||
QueryCriteria compositeCriteria = and(dealCriteriaAll, vaultCriteria);
|
QueryCriteria compositeCriteria = and(dealCriteriaAll, vaultCriteria);
|
||||||
@ -198,7 +199,7 @@ public class VaultQueryJavaTests {
|
|||||||
QueryCriteria vaultCriteria = new VaultQueryCriteria(Vault.StateStatus.UNCONSUMED, null, contractStateTypes);
|
QueryCriteria vaultCriteria = new VaultQueryCriteria(Vault.StateStatus.UNCONSUMED, null, contractStateTypes);
|
||||||
|
|
||||||
List<UniqueIdentifier> linearIds = Arrays.asList(uid);
|
List<UniqueIdentifier> linearIds = Arrays.asList(uid);
|
||||||
List<String> dealPartyNames = Arrays.asList(getMEGA_CORP().getName());
|
List<X500Name> dealPartyNames = Arrays.asList(getMEGA_CORP().getName());
|
||||||
QueryCriteria dealCriteriaAll = new LinearStateQueryCriteria(linearIds, false, dealIds, dealPartyNames);
|
QueryCriteria dealCriteriaAll = new LinearStateQueryCriteria(linearIds, false, dealIds, dealPartyNames);
|
||||||
|
|
||||||
QueryCriteria compositeCriteria = and(dealCriteriaAll, vaultCriteria);
|
QueryCriteria compositeCriteria = and(dealCriteriaAll, vaultCriteria);
|
||||||
|
@ -29,7 +29,7 @@ class InteractiveShellTest {
|
|||||||
constructor(b: Int, c: String) : this(b.toString() + c)
|
constructor(b: Int, c: String) : this(b.toString() + c)
|
||||||
constructor(amount: Amount<Currency>) : this(amount.toString())
|
constructor(amount: Amount<Currency>) : this(amount.toString())
|
||||||
constructor(pair: Pair<Amount<Currency>, SecureHash.SHA256>) : this(pair.toString())
|
constructor(pair: Pair<Amount<Currency>, SecureHash.SHA256>) : this(pair.toString())
|
||||||
constructor(party: Party) : this(party.name)
|
constructor(party: Party) : this(party.name.toString())
|
||||||
override fun call() = a
|
override fun call() = a
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class InteractiveShellTest {
|
|||||||
fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "")
|
fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "")
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun party() = check("party: \"$someCorpLegalName\"", someCorpLegalName)
|
fun party() = check("party: \"$someCorpLegalName\"", someCorpLegalName.toString())
|
||||||
|
|
||||||
class DummyFSM(val logic: FlowA) : FlowStateMachine<Any?> {
|
class DummyFSM(val logic: FlowA) : FlowStateMachine<Any?> {
|
||||||
override fun <T : Any> sendAndReceive(receiveType: Class<T>, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>, retrySend: Boolean): UntrustworthyData<T> {
|
override fun <T : Any> sendAndReceive(receiveType: Class<T>, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>, retrySend: Boolean): UntrustworthyData<T> {
|
||||||
|
@ -266,7 +266,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
|
|
||||||
// Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order
|
// Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order
|
||||||
// of gets and puts.
|
// of gets and puts.
|
||||||
private fun makeNodeWithTracking(networkMapAddr: SingleMessageRecipient?, name: String, overrideServices: Map<ServiceInfo, KeyPair>? = null): MockNetwork.MockNode {
|
private fun makeNodeWithTracking(networkMapAddr: SingleMessageRecipient?, name: X500Name, overrideServices: Map<ServiceInfo, KeyPair>? = null): MockNetwork.MockNode {
|
||||||
// Create a node in the mock network ...
|
// Create a node in the mock network ...
|
||||||
return net.createNode(networkMapAddr, -1, object : MockNetwork.Factory {
|
return net.createNode(networkMapAddr, -1, object : MockNetwork.Factory {
|
||||||
override fun create(config: NodeConfiguration,
|
override fun create(config: NodeConfiguration,
|
||||||
|
@ -12,7 +12,7 @@ class FullNodeConfigurationTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `Artemis special characters not permitted in RPC usernames`() {
|
fun `Artemis special characters not permitted in RPC usernames`() {
|
||||||
fun configWithRPCUsername(username: String): FullNodeConfiguration {
|
fun configWithRPCUsername(username: String): FullNodeConfiguration {
|
||||||
return testConfiguration(Paths.get("."), X500Name(ALICE.name), 0).copy(
|
return testConfiguration(Paths.get("."), ALICE.name, 0).copy(
|
||||||
rpcUsers = listOf(User(username, "pass", emptySet())))
|
rpcUsers = listOf(User(username, "pass", emptySet())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ class RequeryConfigurationTest {
|
|||||||
stateStatus = Vault.StateStatus.UNCONSUMED
|
stateStatus = Vault.StateStatus.UNCONSUMED
|
||||||
contractStateClassName = DummyContract.SingleOwnerState::class.java.name
|
contractStateClassName = DummyContract.SingleOwnerState::class.java.name
|
||||||
contractState = DummyContract.SingleOwnerState(owner = DUMMY_PUBKEY_1).serialize(storageKryo()).bytes
|
contractState = DummyContract.SingleOwnerState(owner = DUMMY_PUBKEY_1).serialize(storageKryo()).bytes
|
||||||
notaryName = txn.tx.notary!!.name
|
notaryName = txn.tx.notary!!.name.toString()
|
||||||
notaryKey = txn.tx.notary!!.owningKey.toBase58String()
|
notaryKey = txn.tx.notary!!.owningKey.toBase58String()
|
||||||
recordedTime = Instant.now()
|
recordedTime = Instant.now()
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import net.corda.testing.node.MockKeyManagementService
|
|||||||
import net.corda.testing.node.TestClock
|
import net.corda.testing.node.TestClock
|
||||||
import net.corda.testing.node.makeTestDataSourceProperties
|
import net.corda.testing.node.makeTestDataSourceProperties
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -79,7 +80,8 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
|||||||
|
|
||||||
database.transaction {
|
database.transaction {
|
||||||
val kms = MockKeyManagementService(ALICE_KEY)
|
val kms = MockKeyManagementService(ALICE_KEY)
|
||||||
val mockMessagingService = InMemoryMessagingNetwork(false).InMemoryMessaging(false, InMemoryMessagingNetwork.PeerHandle(0, "None"), AffinityExecutor.ServiceAffinityExecutor("test", 1), database)
|
val nullIdentity = X500Name("cn=None")
|
||||||
|
val mockMessagingService = InMemoryMessagingNetwork(false).InMemoryMessaging(false, InMemoryMessagingNetwork.PeerHandle(0, nullIdentity), AffinityExecutor.ServiceAffinityExecutor("test", 1), database)
|
||||||
services = object : MockServiceHubInternal(overrideClock = testClock, keyManagement = kms, net = mockMessagingService), TestReference {
|
services = object : MockServiceHubInternal(overrideClock = testClock, keyManagement = kms, net = mockMessagingService), TestReference {
|
||||||
override val vaultService: VaultService = NodeVaultService(this, dataSourceProps)
|
override val vaultService: VaultService = NodeVaultService(this, dataSourceProps)
|
||||||
override val testReference = this@NodeSchedulerServiceTest
|
override val testReference = this@NodeSchedulerServiceTest
|
||||||
|
@ -72,7 +72,7 @@ class ArtemisMessagingTests {
|
|||||||
userService = RPCUserServiceImpl(emptyList())
|
userService = RPCUserServiceImpl(emptyList())
|
||||||
config = TestNodeConfiguration(
|
config = TestNodeConfiguration(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
myLegalName = X500Name(ALICE.name),
|
myLegalName = ALICE.name,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||||
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())
|
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())
|
||||||
|
@ -29,6 +29,7 @@ import net.corda.node.utilities.AddOrRemove.REMOVE
|
|||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import net.corda.testing.node.MockNetwork.MockNode
|
import net.corda.testing.node.MockNetwork.MockNode
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.eclipse.jetty.util.BlockingArrayQueue
|
import org.eclipse.jetty.util.BlockingArrayQueue
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -43,7 +44,7 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
|
|||||||
lateinit var alice: MockNode
|
lateinit var alice: MockNode
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val subscriberLegalName = "CN=Subscriber,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"
|
val subscriberLegalName = X500Name("CN=Subscriber,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@ -246,14 +247,14 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
|
|||||||
network.runNetwork()
|
network.runNetwork()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addNewNodeToNetworkMap(legalName: String): MockNode {
|
private fun addNewNodeToNetworkMap(legalName: X500Name): MockNode {
|
||||||
val node = network.createNode(networkMapAddress = mapServiceNode.info.address, legalName = legalName)
|
val node = network.createNode(networkMapAddress = mapServiceNode.info.address, legalName = legalName)
|
||||||
network.runNetwork()
|
network.runNetwork()
|
||||||
lastSerial = System.currentTimeMillis()
|
lastSerial = System.currentTimeMillis()
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newNodeSeparateFromNetworkMap(legalName: String): MockNode {
|
private fun newNodeSeparateFromNetworkMap(legalName: X500Name): MockNode {
|
||||||
return network.createNode(legalName = legalName, nodeFactory = NoNMSNodeFactory)
|
return network.createNode(legalName = legalName, nodeFactory = NoNMSNodeFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class InMemoryIdentityServiceTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `get identity by name with no registered identities`() {
|
fun `get identity by name with no registered identities`() {
|
||||||
val service = InMemoryIdentityService()
|
val service = InMemoryIdentityService()
|
||||||
assertNull(service.partyFromName(ALICE.name))
|
assertNull(service.partyFromX500Name(ALICE.name))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -54,8 +54,8 @@ class InMemoryIdentityServiceTests {
|
|||||||
val service = InMemoryIdentityService()
|
val service = InMemoryIdentityService()
|
||||||
val identities = listOf("Node A", "Node B", "Node C")
|
val identities = listOf("Node A", "Node B", "Node C")
|
||||||
.map { Party(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) }
|
.map { Party(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) }
|
||||||
assertNull(service.partyFromName(identities.first().name))
|
assertNull(service.partyFromX500Name(identities.first().name))
|
||||||
identities.forEach { service.registerIdentity(it) }
|
identities.forEach { service.registerIdentity(it) }
|
||||||
identities.forEach { assertEquals(it, service.partyFromName(it.name)) }
|
identities.forEach { assertEquals(it, service.partyFromX500Name(it.name)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import net.corda.node.services.transactions.ValidatingNotaryService
|
|||||||
import net.corda.node.utilities.transaction
|
import net.corda.node.utilities.transaction
|
||||||
import net.corda.testing.expect
|
import net.corda.testing.expect
|
||||||
import net.corda.testing.expectEvents
|
import net.corda.testing.expectEvents
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import net.corda.testing.initiateSingleShotFlow
|
import net.corda.testing.initiateSingleShotFlow
|
||||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||||
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
|
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
|
||||||
@ -43,6 +44,7 @@ import net.corda.testing.sequence
|
|||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType
|
import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -74,7 +76,7 @@ class StateMachineManagerTests {
|
|||||||
node1 = nodes.first
|
node1 = nodes.first
|
||||||
node2 = nodes.second
|
node2 = nodes.second
|
||||||
val notaryKeyPair = generateKeyPair()
|
val notaryKeyPair = generateKeyPair()
|
||||||
val notaryService = ServiceInfo(ValidatingNotaryService.type, "CN=notary-service-2000,O=R3,OU=corda,L=London,C=UK")
|
val notaryService = ServiceInfo(ValidatingNotaryService.type, getTestX509Name("notary-service-2000"))
|
||||||
val overrideServices = mapOf(Pair(notaryService, notaryKeyPair))
|
val overrideServices = mapOf(Pair(notaryService, notaryKeyPair))
|
||||||
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
|
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
|
||||||
// service addressing.
|
// service addressing.
|
||||||
|
@ -184,7 +184,7 @@ class VaultQueryTests {
|
|||||||
|
|
||||||
|
|
||||||
val CASH_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) }
|
val CASH_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) }
|
||||||
val CASH_NOTARY: Party get() = Party("Notary Service", CASH_NOTARY_KEY.public)
|
val CASH_NOTARY: Party get() = Party(DUMMY_NOTARY.name, CASH_NOTARY_KEY.public)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `unconsumed states by notary`() {
|
fun `unconsumed states by notary`() {
|
||||||
|
@ -8,6 +8,7 @@ import net.corda.core.crypto.X509Utilities
|
|||||||
import net.corda.core.exists
|
import net.corda.core.exists
|
||||||
import net.corda.core.utilities.ALICE
|
import net.corda.core.utilities.ALICE
|
||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -28,7 +29,7 @@ class NetworkRegistrationHelperTest {
|
|||||||
val identities = listOf("CORDA_CLIENT_CA",
|
val identities = listOf("CORDA_CLIENT_CA",
|
||||||
"CORDA_INTERMEDIATE_CA",
|
"CORDA_INTERMEDIATE_CA",
|
||||||
"CORDA_ROOT_CA")
|
"CORDA_ROOT_CA")
|
||||||
.map { X500Name("CN=${it},O=R3,OU=corda,L=London,C=UK") }
|
.map { getTestX509Name(it) }
|
||||||
val certs = identities.map { X509Utilities.createSelfSignedCACert(it).certificate }
|
val certs = identities.map { X509Utilities.createSelfSignedCACert(it).certificate }
|
||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ class NetworkRegistrationHelperTest {
|
|||||||
|
|
||||||
val config = TestNodeConfiguration(
|
val config = TestNodeConfiguration(
|
||||||
baseDirectory = tempFolder.root.toPath(),
|
baseDirectory = tempFolder.root.toPath(),
|
||||||
myLegalName = X500Name(ALICE.name),
|
myLegalName = ALICE.name,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
|
|
||||||
assertFalse(config.keyStoreFile.exists())
|
assertFalse(config.keyStoreFile.exists())
|
||||||
|
@ -72,7 +72,7 @@ fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K.
|
|||||||
|
|
||||||
fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) {
|
fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) {
|
||||||
// Get the identity key of the other side (the recipient).
|
// Get the identity key of the other side (the recipient).
|
||||||
val otherSide: Party = rpc.partyFromName(DUMMY_BANK_B.name) ?: throw IllegalStateException("Could not find counterparty \"${DUMMY_BANK_B.name}\"")
|
val otherSide: Party = rpc.partyFromX500Name(DUMMY_BANK_B.name) ?: throw IllegalStateException("Could not find counterparty \"${DUMMY_BANK_B.name}\"")
|
||||||
|
|
||||||
// Make sure we have the file in storage
|
// Make sure we have the file in storage
|
||||||
if (!rpc.attachmentExists(hash)) {
|
if (!rpc.attachmentExists(hash)) {
|
||||||
|
@ -8,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo
|
|||||||
import net.corda.node.driver.driver
|
import net.corda.node.driver.driver
|
||||||
import net.corda.node.services.transactions.SimpleNotaryService
|
import net.corda.node.services.transactions.SimpleNotaryService
|
||||||
import net.corda.testing.BOC
|
import net.corda.testing.BOC
|
||||||
|
import net.corda.testing.http.HttpUtils
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
@ -21,7 +22,7 @@ class BankOfCordaHttpAPITest {
|
|||||||
startNode(BIGCORP_LEGAL_NAME)
|
startNode(BIGCORP_LEGAL_NAME)
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
|
val nodeBankOfCordaApiAddr = startWebserver(nodeBankOfCorda).getOrThrow().listenAddress
|
||||||
assertTrue(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", BIGCORP_LEGAL_NAME, "1", X500Name(BOC.name))))
|
assertTrue(BankOfCordaClientApi(nodeBankOfCordaApiAddr).requestWebIssue(IssueRequestParams(1000, "USD", BIGCORP_LEGAL_NAME, "1", BOC.name)))
|
||||||
}, isDebug = true)
|
}, isDebug = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ private class BankOfCordaDriver {
|
|||||||
}, isDebug = true)
|
}, isDebug = true)
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
val requestParams = IssueRequestParams(options.valueOf(quantity), options.valueOf(currency), BIGCORP_LEGAL_NAME, "1", X500Name(BOC.name))
|
val requestParams = IssueRequestParams(options.valueOf(quantity), options.valueOf(currency), BIGCORP_LEGAL_NAME, "1", BOC.name)
|
||||||
when (role) {
|
when (role) {
|
||||||
Role.ISSUE_CASH_RPC -> {
|
Role.ISSUE_CASH_RPC -> {
|
||||||
println("Requesting Cash via RPC ...")
|
println("Requesting Cash via RPC ...")
|
||||||
|
@ -36,9 +36,9 @@ class BankOfCordaClientApi(val hostAndPort: HostAndPort) {
|
|||||||
val proxy = client.proxy()
|
val proxy = client.proxy()
|
||||||
|
|
||||||
// Resolve parties via RPC
|
// Resolve parties via RPC
|
||||||
val issueToParty = proxy.partyFromName(params.issueToPartyName)
|
val issueToParty = proxy.partyFromX500Name(params.issueToPartyName)
|
||||||
?: throw Exception("Unable to locate ${params.issueToPartyName} in Network Map Service")
|
?: throw Exception("Unable to locate ${params.issueToPartyName} in Network Map Service")
|
||||||
val issuerBankParty = proxy.partyFromName(params.issuerBankName)
|
val issuerBankParty = proxy.partyFromX500Name(params.issuerBankName)
|
||||||
?: throw Exception("Unable to locate ${params.issuerBankName} in Network Map Service")
|
?: throw Exception("Unable to locate ${params.issuerBankName} in Network Map Service")
|
||||||
|
|
||||||
val amount = Amount(params.amount, currency(params.currency))
|
val amount = Amount(params.amount, currency(params.currency))
|
||||||
|
@ -19,14 +19,8 @@ import javax.ws.rs.core.Response
|
|||||||
@Path("bank")
|
@Path("bank")
|
||||||
class BankOfCordaWebApi(val rpc: CordaRPCOps) {
|
class BankOfCordaWebApi(val rpc: CordaRPCOps) {
|
||||||
data class IssueRequestParams(val amount: Long, val currency: String,
|
data class IssueRequestParams(val amount: Long, val currency: String,
|
||||||
val issueToPartyName: String, val issueToPartyRefAsString: String,
|
val issueToPartyName: X500Name, val issueToPartyRefAsString: String,
|
||||||
val issuerBankName: String) {
|
val issuerBankName: X500Name)
|
||||||
constructor(amount: Long, currency: String,
|
|
||||||
issueToPartyName: X500Name, issueToPartyRefAsString: String,
|
|
||||||
issuerBankName: X500Name) : this(amount, currency,
|
|
||||||
issueToPartyName.toString(), issueToPartyRefAsString,
|
|
||||||
issuerBankName.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
val logger = loggerFor<BankOfCordaWebApi>()
|
val logger = loggerFor<BankOfCordaWebApi>()
|
||||||
@ -47,9 +41,9 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
|
|||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
fun issueAssetRequest(params: IssueRequestParams): Response {
|
fun issueAssetRequest(params: IssueRequestParams): Response {
|
||||||
// Resolve parties via RPC
|
// Resolve parties via RPC
|
||||||
val issueToParty = rpc.partyFromName(params.issueToPartyName)
|
val issueToParty = rpc.partyFromX500Name(params.issueToPartyName)
|
||||||
?: throw Exception("Unable to locate ${params.issueToPartyName} in Network Map Service")
|
?: throw Exception("Unable to locate ${params.issueToPartyName} in Network Map Service")
|
||||||
val issuerBankParty = rpc.partyFromName(params.issuerBankName)
|
val issuerBankParty = rpc.partyFromX500Name(params.issuerBankName)
|
||||||
?: throw Exception("Unable to locate ${params.issuerBankName} in Network Map Service")
|
?: throw Exception("Unable to locate ${params.issuerBankName} in Network Map Service")
|
||||||
|
|
||||||
val amount = Amount(params.amount, currency(params.currency))
|
val amount = Amount(params.amount, currency(params.currency))
|
||||||
|
@ -96,7 +96,7 @@ open class RatesFixFlow(protected val tx: TransactionBuilder,
|
|||||||
class FixQueryFlow(val fixOf: FixOf, val oracle: Party) : FlowLogic<Fix>() {
|
class FixQueryFlow(val fixOf: FixOf, val oracle: Party) : FlowLogic<Fix>() {
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): Fix {
|
override fun call(): Fix {
|
||||||
val deadline = suggestInterestRateAnnouncementTimeWindow(fixOf.name, oracle.name, fixOf.forDay).end
|
val deadline = suggestInterestRateAnnouncementTimeWindow(fixOf.name, oracle.name.toString(), fixOf.forDay).end
|
||||||
// TODO: add deadline to receive
|
// TODO: add deadline to receive
|
||||||
val resp = sendAndReceive<ArrayList<Fix>>(oracle, QueryRequest(listOf(fixOf), deadline))
|
val resp = sendAndReceive<ArrayList<Fix>>(oracle, QueryRequest(listOf(fixOf), deadline))
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ object UpdateBusinessDayFlow {
|
|||||||
*/
|
*/
|
||||||
private fun getRecipients(): Iterable<NodeInfo> {
|
private fun getRecipients(): Iterable<NodeInfo> {
|
||||||
val notaryNodes = serviceHub.networkMapCache.notaryNodes
|
val notaryNodes = serviceHub.networkMapCache.notaryNodes
|
||||||
val partyNodes = (serviceHub.networkMapCache.partyNodes - notaryNodes).sortedBy { it.legalIdentity.name }
|
val partyNodes = (serviceHub.networkMapCache.partyNodes - notaryNodes).sortedBy { it.legalIdentity.name.toString() }
|
||||||
return notaryNodes + partyNodes
|
return notaryNodes + partyNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
require(advertisedServices.containsType(NetworkMapService.type))
|
require(advertisedServices.containsType(NetworkMapService.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = X500Name(DUMMY_MAP.name),
|
myLegalName = DUMMY_MAP.name,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {}
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
require(advertisedServices.containsType(SimpleNotaryService.type))
|
require(advertisedServices.containsType(SimpleNotaryService.type))
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = X500Name(DUMMY_NOTARY.name),
|
myLegalName = DUMMY_NOTARY.name,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
|||||||
entropyRoot: BigInteger): MockNetwork.MockNode {
|
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||||
val cfg = TestNodeConfiguration(
|
val cfg = TestNodeConfiguration(
|
||||||
baseDirectory = config.baseDirectory,
|
baseDirectory = config.baseDirectory,
|
||||||
myLegalName = X500Name(DUMMY_REGULATOR.name),
|
myLegalName = DUMMY_REGULATOR.name,
|
||||||
networkMapService = null)
|
networkMapService = null)
|
||||||
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
|
||||||
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
|
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
|
||||||
|
@ -237,7 +237,7 @@ class NetworkMapVisualiser : Application() {
|
|||||||
} else if (!viewModel.trackerBoxes.containsKey(tracker)) {
|
} else if (!viewModel.trackerBoxes.containsKey(tracker)) {
|
||||||
// New flow started up; add.
|
// New flow started up; add.
|
||||||
val extraLabel = viewModel.simulation.extraNodeLabels[node]
|
val extraLabel = viewModel.simulation.extraNodeLabels[node]
|
||||||
val label = if (extraLabel != null) "${node.info.legalIdentity.name}: $extraLabel" else node.info.legalIdentity.name
|
val label = if (extraLabel != null) "${node.info.legalIdentity.name.toString()}: $extraLabel" else node.info.legalIdentity.name.toString()
|
||||||
val widget = view.buildProgressTrackerWidget(label, tracker.topLevelTracker)
|
val widget = view.buildProgressTrackerWidget(label, tracker.topLevelTracker)
|
||||||
println("Added: $tracker, $widget")
|
println("Added: $tracker, $widget")
|
||||||
viewModel.trackerBoxes[tracker] = widget
|
viewModel.trackerBoxes[tracker] = widget
|
||||||
|
@ -7,9 +7,7 @@ import javafx.scene.layout.StackPane
|
|||||||
import javafx.scene.shape.Circle
|
import javafx.scene.shape.Circle
|
||||||
import javafx.scene.shape.Line
|
import javafx.scene.shape.Line
|
||||||
import javafx.util.Duration
|
import javafx.util.Duration
|
||||||
import net.corda.core.crypto.commonName
|
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
|
||||||
import net.corda.simulation.IRSSimulation
|
import net.corda.simulation.IRSSimulation
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
@ -117,13 +115,13 @@ class VisualiserViewModel {
|
|||||||
bankCount = simulation.banks.size
|
bankCount = simulation.banks.size
|
||||||
serviceCount = simulation.serviceProviders.size + simulation.regulators.size
|
serviceCount = simulation.serviceProviders.size + simulation.regulators.size
|
||||||
for ((index, bank) in simulation.banks.withIndex()) {
|
for ((index, bank) in simulation.banks.withIndex()) {
|
||||||
nodesToWidgets[bank] = makeNodeWidget(bank, "bank", bank.configuration.displayName, NetworkMapVisualiser.NodeType.BANK, index)
|
nodesToWidgets[bank] = makeNodeWidget(bank, "bank", bank.configuration.myLegalName, NetworkMapVisualiser.NodeType.BANK, index)
|
||||||
}
|
}
|
||||||
for ((index, service) in simulation.serviceProviders.withIndex()) {
|
for ((index, service) in simulation.serviceProviders.withIndex()) {
|
||||||
nodesToWidgets[service] = makeNodeWidget(service, "network-service", service.configuration.displayName, NetworkMapVisualiser.NodeType.SERVICE, index)
|
nodesToWidgets[service] = makeNodeWidget(service, "network-service", service.configuration.myLegalName, NetworkMapVisualiser.NodeType.SERVICE, index)
|
||||||
}
|
}
|
||||||
for ((index, service) in simulation.regulators.withIndex()) {
|
for ((index, service) in simulation.regulators.withIndex()) {
|
||||||
nodesToWidgets[service] = makeNodeWidget(service, "regulator", service.configuration.displayName, NetworkMapVisualiser.NodeType.SERVICE, index + simulation.serviceProviders.size)
|
nodesToWidgets[service] = makeNodeWidget(service, "regulator", service.configuration.myLegalName, NetworkMapVisualiser.NodeType.SERVICE, index + simulation.serviceProviders.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,10 +219,4 @@ class VisualiserViewModel {
|
|||||||
view.root.children.add(bullet)
|
view.root.children.add(bullet)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val NodeConfiguration.displayName: String get() = try {
|
|
||||||
X500Name(myLegalName).commonName
|
|
||||||
} catch(ex: IllegalArgumentException) {
|
|
||||||
myLegalName
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ apply plugin: 'maven-publish'
|
|||||||
ext {
|
ext {
|
||||||
deployTo = "./build/nodes"
|
deployTo = "./build/nodes"
|
||||||
notaryType = "corda.notary.validating.raft"
|
notaryType = "corda.notary.validating.raft"
|
||||||
notaryName = "Raft"
|
notaryName = "CN=Raft,O=R3,OU=corda,L=Zurich,C=CH"
|
||||||
advertisedNotary = "$notaryType|$notaryName"
|
advertisedNotary = "$notaryType|$notaryName"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import net.corda.core.transactions.SignedTransaction
|
|||||||
import net.corda.flows.NotaryFlow
|
import net.corda.flows.NotaryFlow
|
||||||
import net.corda.nodeapi.config.SSLConfiguration
|
import net.corda.nodeapi.config.SSLConfiguration
|
||||||
import net.corda.notarydemo.flows.DummyIssueAndMove
|
import net.corda.notarydemo.flows.DummyIssueAndMove
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
@ -38,7 +39,7 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) {
|
|||||||
private val counterpartyNode by lazy {
|
private val counterpartyNode by lazy {
|
||||||
val (parties, partyUpdates) = rpc.networkMapUpdates()
|
val (parties, partyUpdates) = rpc.networkMapUpdates()
|
||||||
partyUpdates.notUsed()
|
partyUpdates.notUsed()
|
||||||
parties.first { it.legalIdentity.name == "CN=Counterparty,O=R3,OU=corda,L=London,C=UK" }
|
parties.first { it.legalIdentity.name == X500Name("CN=Counterparty,O=R3,OU=corda,L=London,C=UK") }
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
@ -16,6 +16,7 @@ import net.corda.vega.api.PortfolioApiUtils
|
|||||||
import net.corda.vega.api.SwapDataModel
|
import net.corda.vega.api.SwapDataModel
|
||||||
import net.corda.vega.api.SwapDataView
|
import net.corda.vega.api.SwapDataView
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -49,7 +50,7 @@ class SimmValuationTest : IntegrationTestCategory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPartyWithName(partyApi: HttpApi, counterparty: String): PortfolioApi.ApiParty =
|
private fun getPartyWithName(partyApi: HttpApi, counterparty: X500Name): PortfolioApi.ApiParty =
|
||||||
getAvailablePartiesFor(partyApi).counterparties.single { it.text == counterparty }
|
getAvailablePartiesFor(partyApi).counterparties.single { it.text == counterparty }
|
||||||
|
|
||||||
private fun getAvailablePartiesFor(partyApi: HttpApi): PortfolioApi.AvailableParties {
|
private fun getAvailablePartiesFor(partyApi: HttpApi): PortfolioApi.AvailableParties {
|
||||||
|
@ -20,6 +20,7 @@ import net.corda.vega.flows.SimmRevaluation
|
|||||||
import net.corda.vega.portfolio.Portfolio
|
import net.corda.vega.portfolio.Portfolio
|
||||||
import net.corda.vega.portfolio.toPortfolio
|
import net.corda.vega.portfolio.toPortfolio
|
||||||
import net.corda.vega.portfolio.toStateAndRef
|
import net.corda.vega.portfolio.toStateAndRef
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
@ -240,7 +241,7 @@ class PortfolioApi(val rpc: CordaRPCOps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ApiParty(val id: String, val text: String)
|
data class ApiParty(val id: String, val text: X500Name)
|
||||||
data class AvailableParties(val self: ApiParty, val counterparties: List<ApiParty>)
|
data class AvailableParties(val self: ApiParty, val counterparties: List<ApiParty>)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,6 +18,7 @@ import net.corda.core.utilities.loggerFor
|
|||||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||||
import net.corda.testing.BOC
|
import net.corda.testing.BOC
|
||||||
import net.corda.traderdemo.flow.SellerFlow
|
import net.corda.traderdemo.flow.SellerFlow
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,7 +44,7 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun runBuyer(amount: Amount<Currency> = 30000.DOLLARS) {
|
fun runBuyer(amount: Amount<Currency> = 30000.DOLLARS) {
|
||||||
val bankOfCordaParty = rpc.partyFromName(BOC.name)
|
val bankOfCordaParty = rpc.partyFromX500Name(BOC.name)
|
||||||
?: throw Exception("Unable to locate ${BOC.name} in Network Map Service")
|
?: throw Exception("Unable to locate ${BOC.name} in Network Map Service")
|
||||||
val me = rpc.nodeIdentity()
|
val me = rpc.nodeIdentity()
|
||||||
val amounts = calculateRandomlySizedAmounts(amount, 3, 10, Random())
|
val amounts = calculateRandomlySizedAmounts(amount, 3, 10, Random())
|
||||||
@ -55,8 +56,8 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
|
|||||||
Futures.allAsList(resultFutures).getOrThrow()
|
Futures.allAsList(resultFutures).getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runSeller(amount: Amount<Currency> = 1000.0.DOLLARS, counterparty: String) {
|
fun runSeller(amount: Amount<Currency> = 1000.0.DOLLARS, counterparty: X500Name) {
|
||||||
val otherParty = rpc.partyFromName(counterparty) ?: throw IllegalStateException("Don't know $counterparty")
|
val otherParty = rpc.partyFromX500Name(counterparty) ?: throw IllegalStateException("Don't know $counterparty")
|
||||||
// The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash.
|
// The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash.
|
||||||
//
|
//
|
||||||
// The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an
|
// The CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an
|
||||||
|
@ -6,10 +6,8 @@ package net.corda.testing
|
|||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.X509Utilities.getX509Name
|
||||||
import net.corda.core.crypto.X509Utilities
|
|
||||||
import net.corda.core.crypto.generateKeyPair
|
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.VersionInfo
|
import net.corda.core.node.VersionInfo
|
||||||
@ -28,6 +26,7 @@ import net.corda.testing.node.MockIdentityService
|
|||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.makeTestDataSourceProperties
|
import net.corda.testing.node.makeTestDataSourceProperties
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x500.X500NameBuilder
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
@ -75,7 +74,7 @@ val MINI_CORP: Party get() = Party(X509Utilities.getDevX509Name("MiniCorp"), MIN
|
|||||||
|
|
||||||
val BOC_KEY: KeyPair by lazy { generateKeyPair() }
|
val BOC_KEY: KeyPair by lazy { generateKeyPair() }
|
||||||
val BOC_PUBKEY: PublicKey get() = BOC_KEY.public
|
val BOC_PUBKEY: PublicKey get() = BOC_KEY.public
|
||||||
val BOC: Party get() = Party(X500Name("CN=BankOfCorda,O=R3,OU=corda,L=New York,C=US"), BOC_PUBKEY)
|
val BOC: Party get() = Party(getTestX509Name("BankOfCorda"), BOC_PUBKEY)
|
||||||
val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference
|
val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference
|
||||||
|
|
||||||
val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() }
|
val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() }
|
||||||
@ -163,7 +162,7 @@ data class TestNodeConfiguration(
|
|||||||
override val keyStorePassword: String = "cordacadevpass",
|
override val keyStorePassword: String = "cordacadevpass",
|
||||||
override val trustStorePassword: String = "trustpass",
|
override val trustStorePassword: String = "trustpass",
|
||||||
override val rpcUsers: List<User> = emptyList(),
|
override val rpcUsers: List<User> = emptyList(),
|
||||||
override val dataSourceProperties: Properties = makeTestDataSourceProperties(myLegalName),
|
override val dataSourceProperties: Properties = makeTestDataSourceProperties(myLegalName.commonName),
|
||||||
override val emailAddress: String = "",
|
override val emailAddress: String = "",
|
||||||
override val exportJMXto: String = "",
|
override val exportJMXto: String = "",
|
||||||
override val devMode: Boolean = true,
|
override val devMode: Boolean = true,
|
||||||
@ -183,7 +182,7 @@ fun testConfiguration(baseDirectory: Path, legalName: X500Name, basePort: Int):
|
|||||||
emailAddress = "",
|
emailAddress = "",
|
||||||
keyStorePassword = "cordacadevpass",
|
keyStorePassword = "cordacadevpass",
|
||||||
trustStorePassword = "trustpass",
|
trustStorePassword = "trustpass",
|
||||||
dataSourceProperties = makeTestDataSourceProperties(legalName),
|
dataSourceProperties = makeTestDataSourceProperties(legalName.commonName),
|
||||||
certificateSigningService = URL("http://localhost"),
|
certificateSigningService = URL("http://localhost"),
|
||||||
rpcUsers = emptyList(),
|
rpcUsers = emptyList(),
|
||||||
verifierType = VerifierType.InMemory,
|
verifierType = VerifierType.InMemory,
|
||||||
@ -200,7 +199,7 @@ fun testConfiguration(baseDirectory: Path, legalName: X500Name, basePort: Int):
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun configureTestSSL(legalName: X500Name = X500Name(MEGA_CORP.name)): SSLConfiguration = object : SSLConfiguration {
|
fun configureTestSSL(legalName: X500Name = MEGA_CORP.name): SSLConfiguration = object : SSLConfiguration {
|
||||||
override val certificatesDirectory = Files.createTempDirectory("certs")
|
override val certificatesDirectory = Files.createTempDirectory("certs")
|
||||||
override val keyStorePassword: String get() = "cordacadevpass"
|
override val keyStorePassword: String get() = "cordacadevpass"
|
||||||
override val trustStorePassword: String get() = "trustpass"
|
override val trustStorePassword: String get() = "trustpass"
|
||||||
@ -209,3 +208,19 @@ fun configureTestSSL(legalName: X500Name = X500Name(MEGA_CORP.name)): SSLConfigu
|
|||||||
configureDevKeyAndTrustStores(legalName)
|
configureDevKeyAndTrustStores(legalName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a bogus X.509 for testing purposes.
|
||||||
|
*/
|
||||||
|
fun getTestX509Name(commonName: String): X500Name {
|
||||||
|
require(!commonName.startsWith("CN="))
|
||||||
|
// TODO: Consider if we want to make these more variable, i.e. different locations?
|
||||||
|
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
|
||||||
|
nameBuilder.addRDN(BCStyle.CN, commonName)
|
||||||
|
nameBuilder.addRDN(BCStyle.O, "R3")
|
||||||
|
nameBuilder.addRDN(BCStyle.OU, "Corda QA Department")
|
||||||
|
nameBuilder.addRDN(BCStyle.L, "New York")
|
||||||
|
nameBuilder.addRDN(BCStyle.C, "US")
|
||||||
|
return nameBuilder.build()
|
||||||
|
}
|
@ -22,7 +22,7 @@ object HttpUtils {
|
|||||||
.readTimeout(60, TimeUnit.SECONDS).build()
|
.readTimeout(60, TimeUnit.SECONDS).build()
|
||||||
}
|
}
|
||||||
val defaultMapper: ObjectMapper by lazy {
|
val defaultMapper: ObjectMapper by lazy {
|
||||||
ObjectMapper().registerModule(JavaTimeModule()).registerModule(KotlinModule())
|
net.corda.jackson.JacksonSupport.createNonRpcMapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putJson(url: URL, data: String): Boolean {
|
fun putJson(url: URL, data: String): Boolean {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.testing.messaging
|
package net.corda.testing.messaging
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.nodeapi.ArtemisMessagingComponent
|
import net.corda.nodeapi.ArtemisMessagingComponent
|
||||||
import net.corda.nodeapi.ArtemisTcpTransport
|
import net.corda.nodeapi.ArtemisTcpTransport
|
||||||
import net.corda.nodeapi.ConnectionDirection
|
import net.corda.nodeapi.ConnectionDirection
|
||||||
|
@ -9,6 +9,7 @@ import net.corda.core.node.NodeInfo
|
|||||||
import net.corda.core.node.services.NetworkMapCache
|
import net.corda.core.node.services.NetworkMapCache
|
||||||
import net.corda.node.services.network.InMemoryNetworkMapCache
|
import net.corda.node.services.network.InMemoryNetworkMapCache
|
||||||
import net.corda.testing.MOCK_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
@ -18,8 +19,8 @@ import rx.subjects.PublishSubject
|
|||||||
*/
|
*/
|
||||||
class MockNetworkMapCache : InMemoryNetworkMapCache() {
|
class MockNetworkMapCache : InMemoryNetworkMapCache() {
|
||||||
private companion object {
|
private companion object {
|
||||||
val BANK_C = Party(X500Name("CN=Bank C,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"), DummyPublicKey("Bank C"))
|
val BANK_C = Party(getTestX509Name("Bank C"), DummyPublicKey("Bank C"))
|
||||||
val BANK_D = Party(X500Name("CN=Bank D,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"), DummyPublicKey("Bank D"))
|
val BANK_D = Party(getTestX509Name("Bank D"), DummyPublicKey("Bank D"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val changed: Observable<NetworkMapCache.MapChange> = PublishSubject.create<NetworkMapCache.MapChange>()
|
override val changed: Observable<NetworkMapCache.MapChange> = PublishSubject.create<NetworkMapCache.MapChange>()
|
||||||
|
@ -7,6 +7,8 @@ import com.google.common.util.concurrent.Futures
|
|||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.crypto.entropyToKeyPair
|
import net.corda.core.crypto.entropyToKeyPair
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
@ -34,6 +36,7 @@ import net.corda.node.utilities.AffinityExecutor
|
|||||||
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||||
import net.corda.testing.MOCK_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.TestNodeConfiguration
|
import net.corda.testing.TestNodeConfiguration
|
||||||
|
import net.corda.testing.getTestX509Name
|
||||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
@ -264,7 +267,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
||||||
*/
|
*/
|
||||||
fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
|
fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
|
||||||
start: Boolean = true, legalName: String? = null, overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
start: Boolean = true, legalName: X500Name? = null, overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
||||||
vararg advertisedServices: ServiceInfo): MockNode
|
vararg advertisedServices: ServiceInfo): MockNode
|
||||||
= createNode(networkMapAddress, forcedID, nodeFactory, start, legalName, overrideServices, BigInteger.valueOf(random63BitValue()), *advertisedServices)
|
= createNode(networkMapAddress, forcedID, nodeFactory, start, legalName, overrideServices, BigInteger.valueOf(random63BitValue()), *advertisedServices)
|
||||||
|
|
||||||
@ -276,7 +279,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
|
||||||
*/
|
*/
|
||||||
fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
|
fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int = -1, nodeFactory: Factory = defaultFactory,
|
||||||
start: Boolean = true, legalName: String? = null, overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
start: Boolean = true, legalName: X500Name? = null, overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
||||||
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
|
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
|
||||||
vararg advertisedServices: ServiceInfo): MockNode {
|
vararg advertisedServices: ServiceInfo): MockNode {
|
||||||
val newNode = forcedID == -1
|
val newNode = forcedID == -1
|
||||||
@ -288,9 +291,9 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
|
|
||||||
val config = TestNodeConfiguration(
|
val config = TestNodeConfiguration(
|
||||||
baseDirectory = path,
|
baseDirectory = path,
|
||||||
myLegalName = X500Name(legalName ?: "CN=Mock Company $id,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"),
|
myLegalName = legalName ?: getTestX509Name("Mock Company $id"),
|
||||||
networkMapService = null,
|
networkMapService = null,
|
||||||
dataSourceProperties = makeTestDataSourceProperties(X500Name("CN=node_${id}_net_$networkId,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")))
|
dataSourceProperties = makeTestDataSourceProperties("node_${id}_net_$networkId"))
|
||||||
val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, overrideServices, entropyRoot)
|
val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, overrideServices, entropyRoot)
|
||||||
if (start) {
|
if (start) {
|
||||||
node.setup().start()
|
node.setup().start()
|
||||||
@ -327,8 +330,8 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
* Sets up a two node network, in which the first node runs network map and notary services and the other
|
* Sets up a two node network, in which the first node runs network map and notary services and the other
|
||||||
* doesn't.
|
* doesn't.
|
||||||
*/
|
*/
|
||||||
fun createTwoNodes(firstNodeName: String? = null,
|
fun createTwoNodes(firstNodeName: X500Name? = null,
|
||||||
secondNodeName: String? = null,
|
secondNodeName: X500Name? = null,
|
||||||
nodeFactory: Factory = defaultFactory,
|
nodeFactory: Factory = defaultFactory,
|
||||||
notaryKeyPair: KeyPair? = null): Pair<MockNode, MockNode> {
|
notaryKeyPair: KeyPair? = null): Pair<MockNode, MockNode> {
|
||||||
require(nodes.isEmpty())
|
require(nodes.isEmpty())
|
||||||
@ -372,15 +375,15 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createNotaryNode(networkMapAddr: SingleMessageRecipient? = null,
|
fun createNotaryNode(networkMapAddr: SingleMessageRecipient? = null,
|
||||||
legalName: String? = null,
|
legalName: X500Name? = null,
|
||||||
overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
overrideServices: Map<ServiceInfo, KeyPair>? = null,
|
||||||
serviceName: String? = null): MockNode {
|
serviceName: X500Name? = null): MockNode {
|
||||||
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices, BigInteger.valueOf(random63BitValue()),
|
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices, BigInteger.valueOf(random63BitValue()),
|
||||||
ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName))
|
ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPartyNode(networkMapAddr: SingleMessageRecipient,
|
fun createPartyNode(networkMapAddr: SingleMessageRecipient,
|
||||||
legalName: String? = null,
|
legalName: X500Name? = null,
|
||||||
overrideServices: Map<ServiceInfo, KeyPair>? = null): MockNode {
|
overrideServices: Map<ServiceInfo, KeyPair>? = null): MockNode {
|
||||||
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices)
|
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices)
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub {
|
|||||||
class MockIdentityService(val identities: List<Party>) : IdentityService, SingletonSerializeAsToken() {
|
class MockIdentityService(val identities: List<Party>) : IdentityService, SingletonSerializeAsToken() {
|
||||||
private val keyToParties: Map<PublicKey, Party>
|
private val keyToParties: Map<PublicKey, Party>
|
||||||
get() = synchronized(identities) { identities.associateBy { it.owningKey } }
|
get() = synchronized(identities) { identities.associateBy { it.owningKey } }
|
||||||
private val nameToParties: Map<String, Party>
|
private val nameToParties: Map<X500Name, Party>
|
||||||
get() = synchronized(identities) { identities.associateBy { it.name } }
|
get() = synchronized(identities) { identities.associateBy { it.name } }
|
||||||
|
|
||||||
override fun registerIdentity(party: Party) {
|
override fun registerIdentity(party: Party) {
|
||||||
@ -85,8 +85,8 @@ class MockIdentityService(val identities: List<Party>) : IdentityService, Single
|
|||||||
override fun partyFromAnonymous(party: AnonymousParty): Party? = keyToParties[party.owningKey]
|
override fun partyFromAnonymous(party: AnonymousParty): Party? = keyToParties[party.owningKey]
|
||||||
override fun partyFromAnonymous(partyRef: PartyAndReference): Party? = partyFromAnonymous(partyRef.party)
|
override fun partyFromAnonymous(partyRef: PartyAndReference): Party? = partyFromAnonymous(partyRef.party)
|
||||||
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
|
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
|
||||||
override fun partyFromName(name: String): Party? = nameToParties[name]
|
override fun partyFromName(name: String): Party? = nameToParties[X500Name(name)]
|
||||||
override fun partyFromX500Name(principal: X500Name): Party? = nameToParties[principal.toString()]
|
override fun partyFromX500Name(principal: X500Name): Party? = nameToParties[principal]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -176,7 +176,8 @@ class MockStorageService(override val attachments: AttachmentStorage = MockAttac
|
|||||||
*
|
*
|
||||||
* @param nodeName Reflects the "instance" of the in-memory database. Defaults to a random string.
|
* @param nodeName Reflects the "instance" of the in-memory database. Defaults to a random string.
|
||||||
*/
|
*/
|
||||||
fun makeTestDataSourceProperties(nodeName: X500Name = X509Utilities.getDevX509Name(SecureHash.randomSHA256().toString())): Properties {
|
// TODO: Can we use an X509 principal generator here?
|
||||||
|
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
||||||
val props = Properties()
|
val props = Properties()
|
||||||
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
||||||
props.setProperty("dataSource.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
props.setProperty("dataSource.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
||||||
|
@ -3,6 +3,8 @@ package net.corda.testing.node
|
|||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.core.createDirectories
|
import net.corda.core.createDirectories
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.flatMap
|
import net.corda.core.flatMap
|
||||||
import net.corda.core.map
|
import net.corda.core.map
|
||||||
@ -19,6 +21,7 @@ import net.corda.nodeapi.config.parseAs
|
|||||||
import net.corda.testing.MOCK_VERSION_INFO
|
import net.corda.testing.MOCK_VERSION_INFO
|
||||||
import net.corda.testing.getFreeLocalPorts
|
import net.corda.testing.getFreeLocalPorts
|
||||||
import org.apache.logging.log4j.Level
|
import org.apache.logging.log4j.Level
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
@ -59,7 +62,7 @@ abstract class NodeBasedTest {
|
|||||||
* You can use this method to start the network map node in a more customised manner. Otherwise it
|
* You can use this method to start the network map node in a more customised manner. Otherwise it
|
||||||
* will automatically be started with the default parameters.
|
* will automatically be started with the default parameters.
|
||||||
*/
|
*/
|
||||||
fun startNetworkMapNode(legalName: String = DUMMY_MAP.name,
|
fun startNetworkMapNode(legalName: X500Name = DUMMY_MAP.name,
|
||||||
platformVersion: Int = 1,
|
platformVersion: Int = 1,
|
||||||
advertisedServices: Set<ServiceInfo> = emptySet(),
|
advertisedServices: Set<ServiceInfo> = emptySet(),
|
||||||
rpcUsers: List<User> = emptyList(),
|
rpcUsers: List<User> = emptyList(),
|
||||||
@ -70,7 +73,7 @@ abstract class NodeBasedTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startNode(legalName: String,
|
fun startNode(legalName: X500Name,
|
||||||
platformVersion: Int = 1,
|
platformVersion: Int = 1,
|
||||||
advertisedServices: Set<ServiceInfo> = emptySet(),
|
advertisedServices: Set<ServiceInfo> = emptySet(),
|
||||||
rpcUsers: List<User> = emptyList(),
|
rpcUsers: List<User> = emptyList(),
|
||||||
@ -83,18 +86,18 @@ abstract class NodeBasedTest {
|
|||||||
mapOf(
|
mapOf(
|
||||||
"networkMapService" to mapOf(
|
"networkMapService" to mapOf(
|
||||||
"address" to networkMapNode.configuration.p2pAddress.toString(),
|
"address" to networkMapNode.configuration.p2pAddress.toString(),
|
||||||
"legalName" to networkMapNode.info.legalIdentity.name
|
"legalName" to networkMapNode.info.legalIdentity.name.toString()
|
||||||
)
|
)
|
||||||
) + configOverrides
|
) + configOverrides
|
||||||
)
|
)
|
||||||
return node.networkMapRegistrationFuture.map { node }
|
return node.networkMapRegistrationFuture.map { node }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startNotaryCluster(notaryName: String,
|
fun startNotaryCluster(notaryName: X500Name,
|
||||||
clusterSize: Int,
|
clusterSize: Int,
|
||||||
serviceType: ServiceType = RaftValidatingNotaryService.type): ListenableFuture<List<Node>> {
|
serviceType: ServiceType = RaftValidatingNotaryService.type): ListenableFuture<List<Node>> {
|
||||||
ServiceIdentityGenerator.generateToDisk(
|
ServiceIdentityGenerator.generateToDisk(
|
||||||
(0 until clusterSize).map { tempFolder.root.toPath() / "$notaryName-$it" },
|
(0 until clusterSize).map { tempFolder.root.toPath() / "${notaryName.commonName}-$it" },
|
||||||
serviceType.id,
|
serviceType.id,
|
||||||
notaryName)
|
notaryName)
|
||||||
|
|
||||||
@ -102,13 +105,13 @@ abstract class NodeBasedTest {
|
|||||||
val nodeAddresses = getFreeLocalPorts("localhost", clusterSize).map { it.toString() }
|
val nodeAddresses = getFreeLocalPorts("localhost", clusterSize).map { it.toString() }
|
||||||
|
|
||||||
val masterNodeFuture = startNode(
|
val masterNodeFuture = startNode(
|
||||||
"$notaryName-0",
|
X509Utilities.getDevX509Name("${notaryName.commonName}-0"),
|
||||||
advertisedServices = setOf(serviceInfo),
|
advertisedServices = setOf(serviceInfo),
|
||||||
configOverrides = mapOf("notaryNodeAddress" to nodeAddresses[0]))
|
configOverrides = mapOf("notaryNodeAddress" to nodeAddresses[0]))
|
||||||
|
|
||||||
val remainingNodesFutures = (1 until clusterSize).map {
|
val remainingNodesFutures = (1 until clusterSize).map {
|
||||||
startNode(
|
startNode(
|
||||||
"$notaryName-$it",
|
X509Utilities.getDevX509Name("${notaryName.commonName}-$it"),
|
||||||
advertisedServices = setOf(serviceInfo),
|
advertisedServices = setOf(serviceInfo),
|
||||||
configOverrides = mapOf(
|
configOverrides = mapOf(
|
||||||
"notaryNodeAddress" to nodeAddresses[it],
|
"notaryNodeAddress" to nodeAddresses[it],
|
||||||
@ -120,18 +123,18 @@ abstract class NodeBasedTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startNodeInternal(legalName: String,
|
private fun startNodeInternal(legalName: X500Name,
|
||||||
platformVersion: Int,
|
platformVersion: Int,
|
||||||
advertisedServices: Set<ServiceInfo>,
|
advertisedServices: Set<ServiceInfo>,
|
||||||
rpcUsers: List<User>,
|
rpcUsers: List<User>,
|
||||||
configOverrides: Map<String, Any>): Node {
|
configOverrides: Map<String, Any>): Node {
|
||||||
val baseDirectory = (tempFolder.root.toPath() / legalName).createDirectories()
|
val baseDirectory = (tempFolder.root.toPath() / legalName.commonName).createDirectories()
|
||||||
val localPort = getFreeLocalPorts("localhost", 2)
|
val localPort = getFreeLocalPorts("localhost", 2)
|
||||||
val config = ConfigHelper.loadConfig(
|
val config = ConfigHelper.loadConfig(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
allowMissingConfig = true,
|
allowMissingConfig = true,
|
||||||
configOverrides = mapOf(
|
configOverrides = mapOf(
|
||||||
"myLegalName" to legalName,
|
"myLegalName" to legalName.toString(),
|
||||||
"p2pAddress" to localPort[0].toString(),
|
"p2pAddress" to localPort[0].toString(),
|
||||||
"rpcAddress" to localPort[1].toString(),
|
"rpcAddress" to localPort[1].toString(),
|
||||||
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
|
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
|
||||||
@ -148,7 +151,7 @@ abstract class NodeBasedTest {
|
|||||||
val node = config.parseAs<FullNodeConfiguration>().createNode(MOCK_VERSION_INFO.copy(platformVersion = platformVersion))
|
val node = config.parseAs<FullNodeConfiguration>().createNode(MOCK_VERSION_INFO.copy(platformVersion = platformVersion))
|
||||||
node.start()
|
node.start()
|
||||||
nodes += node
|
nodes += node
|
||||||
thread(name = legalName) {
|
thread(name = legalName.commonName) {
|
||||||
node.run()
|
node.run()
|
||||||
}
|
}
|
||||||
return node
|
return node
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.demobench.model
|
package net.corda.demobench.model
|
||||||
|
|
||||||
import com.typesafe.config.*
|
import com.typesafe.config.*
|
||||||
|
import net.corda.core.crypto.location
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||||
@ -26,7 +27,7 @@ class NodeConfig(
|
|||||||
val defaultUser = user("guest")
|
val defaultUser = user("guest")
|
||||||
}
|
}
|
||||||
|
|
||||||
val nearestCity: String? = legalName.getRDNs(BCStyle.L).singleOrNull()?.typesAndValues?.singleOrNull()?.value?.toString()
|
val nearestCity: String? = legalName.location
|
||||||
val nodeDir: Path = baseDir.resolve(key)
|
val nodeDir: Path = baseDir.resolve(key)
|
||||||
override val pluginDir: Path = nodeDir.resolve("plugins")
|
override val pluginDir: Path = nodeDir.resolve("plugins")
|
||||||
val explorerDir: Path = baseDir.resolve("$key-explorer")
|
val explorerDir: Path = baseDir.resolve("$key-explorer")
|
||||||
|
@ -144,7 +144,7 @@ class NodeConfigTest {
|
|||||||
assertEquals(prettyPrint("{"
|
assertEquals(prettyPrint("{"
|
||||||
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
||||||
+ "\"h2port\":30001,"
|
+ "\"h2port\":30001,"
|
||||||
+ "\"myLegalName\":\"My Name\","
|
+ "\"myLegalName\":\"CN=My Name,OU=Corda QA Department,O=R3 CEV,L=New York,C=US\","
|
||||||
+ "\"p2pAddress\":\"localhost:10001\","
|
+ "\"p2pAddress\":\"localhost:10001\","
|
||||||
+ "\"rpcAddress\":\"localhost:40002\","
|
+ "\"rpcAddress\":\"localhost:40002\","
|
||||||
+ "\"rpcUsers\":["
|
+ "\"rpcUsers\":["
|
||||||
@ -166,12 +166,12 @@ class NodeConfigTest {
|
|||||||
services = listOf("my.service"),
|
services = listOf("my.service"),
|
||||||
users = listOf(user("jenny"))
|
users = listOf(user("jenny"))
|
||||||
)
|
)
|
||||||
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
||||||
|
|
||||||
assertEquals(prettyPrint("{"
|
assertEquals(prettyPrint("{"
|
||||||
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
|
||||||
+ "\"h2port\":30001,"
|
+ "\"h2port\":30001,"
|
||||||
+ "\"myLegalName\":\"My Name\","
|
+ "\"myLegalName\":\"CN=My Name,OU=Corda QA Department,O=R3 CEV,L=New York,C=US\","
|
||||||
+ "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH\"},"
|
+ "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH\"},"
|
||||||
+ "\"p2pAddress\":\"localhost:10001\","
|
+ "\"p2pAddress\":\"localhost:10001\","
|
||||||
+ "\"rpcAddress\":\"localhost:40002\","
|
+ "\"rpcAddress\":\"localhost:40002\","
|
||||||
@ -194,7 +194,7 @@ class NodeConfigTest {
|
|||||||
services = listOf("my.service"),
|
services = listOf("my.service"),
|
||||||
users = listOf(user("jenny"))
|
users = listOf(user("jenny"))
|
||||||
)
|
)
|
||||||
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
||||||
|
|
||||||
val nodeConfig = config.toFileConfig()
|
val nodeConfig = config.toFileConfig()
|
||||||
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
||||||
@ -203,7 +203,6 @@ class NodeConfigTest {
|
|||||||
val fullConfig = nodeConfig.parseAs<FullNodeConfiguration>()
|
val fullConfig = nodeConfig.parseAs<FullNodeConfiguration>()
|
||||||
|
|
||||||
assertEquals(myLegalName, fullConfig.myLegalName)
|
assertEquals(myLegalName, fullConfig.myLegalName)
|
||||||
assertEquals("London", fullConfig.nearestCity)
|
|
||||||
assertEquals(localPort(40002), fullConfig.rpcAddress)
|
assertEquals(localPort(40002), fullConfig.rpcAddress)
|
||||||
assertEquals(localPort(10001), fullConfig.p2pAddress)
|
assertEquals(localPort(10001), fullConfig.p2pAddress)
|
||||||
assertEquals(listOf("my.service"), fullConfig.extraAdvertisedServiceIds)
|
assertEquals(listOf("my.service"), fullConfig.extraAdvertisedServiceIds)
|
||||||
@ -224,7 +223,7 @@ class NodeConfigTest {
|
|||||||
services = listOf("my.service"),
|
services = listOf("my.service"),
|
||||||
users = listOf(user("jenny"))
|
users = listOf(user("jenny"))
|
||||||
)
|
)
|
||||||
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
|
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
|
||||||
|
|
||||||
val nodeConfig = config.toFileConfig()
|
val nodeConfig = config.toFileConfig()
|
||||||
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
|
||||||
|
@ -101,7 +101,7 @@ class NodeControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test register non-network-map node`() {
|
fun `test register non-network-map node`() {
|
||||||
val config = createConfig(legalName = X500Name("CN=Node is not Network Map,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
val config = createConfig(legalName = X500Name("CN=Node is not Network Map,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"))
|
||||||
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 10000)
|
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 10000)
|
||||||
assertFalse(config.isNetworkMap())
|
assertFalse(config.isNetworkMap())
|
||||||
|
|
||||||
assertFalse(controller.hasNetworkMap())
|
assertFalse(controller.hasNetworkMap())
|
||||||
|
@ -266,7 +266,7 @@ fun main(args: Array<String>) {
|
|||||||
// Party pay requests.
|
// Party pay requests.
|
||||||
eventGenerator.moveCashGenerator.combine(Generator.pickOne(parties)) { command, (party, rpc) ->
|
eventGenerator.moveCashGenerator.combine(Generator.pickOne(parties)) { command, (party, rpc) ->
|
||||||
println("${Instant.now()} [$i] SENDING ${command.amount} from $party to ${command.recipient}")
|
println("${Instant.now()} [$i] SENDING ${command.amount} from $party to ${command.recipient}")
|
||||||
command.startFlow(rpc).log(i, party.name)
|
command.startFlow(rpc).log(i, party.name.toString())
|
||||||
}.generate(SplittableRandom())
|
}.generate(SplittableRandom())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ import net.corda.core.crypto.commonName
|
|||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
|
||||||
object PartyNameFormatter {
|
object PartyNameFormatter {
|
||||||
val short = object : Formatter<String> {
|
val short = object : Formatter<X500Name> {
|
||||||
override fun format(value: String) = X500Name(value).commonName
|
override fun format(value: X500Name) = value.commonName
|
||||||
}
|
}
|
||||||
|
|
||||||
val full = object : Formatter<String> {
|
val full = object : Formatter<X500Name> {
|
||||||
override fun format(value: String): String = value
|
override fun format(value: X500Name): String = value.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,7 @@ import net.corda.client.jfx.utils.map
|
|||||||
import net.corda.client.jfx.utils.sequence
|
import net.corda.client.jfx.utils.sequence
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.AbstractParty
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.AnonymousParty
|
|
||||||
import net.corda.core.crypto.SecureHash
|
|
||||||
import net.corda.core.crypto.toBase58String
|
|
||||||
import net.corda.core.crypto.toStringShort
|
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.explorer.AmountDiff
|
import net.corda.explorer.AmountDiff
|
||||||
import net.corda.explorer.formatters.AmountFormatter
|
import net.corda.explorer.formatters.AmountFormatter
|
||||||
@ -39,6 +35,7 @@ import net.corda.explorer.model.CordaWidget
|
|||||||
import net.corda.explorer.model.ReportingCurrencyModel
|
import net.corda.explorer.model.ReportingCurrencyModel
|
||||||
import net.corda.explorer.sign
|
import net.corda.explorer.sign
|
||||||
import net.corda.explorer.ui.setCustomCellFactory
|
import net.corda.explorer.ui.setCustomCellFactory
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -110,8 +107,8 @@ class TransactionViewer : CordaView("Transactions") {
|
|||||||
"Transaction ID" to { tx, s -> "${tx.id}".contains(s, true) },
|
"Transaction ID" to { tx, s -> "${tx.id}".contains(s, true) },
|
||||||
"Input" to { tx, s -> tx.inputs.resolved.any { it.state.data.contract.javaClass.simpleName.contains(s, true) } },
|
"Input" to { tx, s -> tx.inputs.resolved.any { it.state.data.contract.javaClass.simpleName.contains(s, true) } },
|
||||||
"Output" to { tx, s -> tx.outputs.any { it.state.data.contract.javaClass.simpleName.contains(s, true) } },
|
"Output" to { tx, s -> tx.outputs.any { it.state.data.contract.javaClass.simpleName.contains(s, true) } },
|
||||||
"Input Party" to { tx, s -> tx.inputParties.any { it.any { it.value?.legalIdentity?.name?.contains(s, true) ?: false } } },
|
"Input Party" to { tx, s -> tx.inputParties.any { it.any { it.value?.legalIdentity?.name?.commonName?.contains(s, true) ?: false } } },
|
||||||
"Output Party" to { tx, s -> tx.outputParties.any { it.any { it.value?.legalIdentity?.name?.contains(s, true) ?: false } } },
|
"Output Party" to { tx, s -> tx.outputParties.any { it.any { it.value?.legalIdentity?.name?.commonName?.contains(s, true) ?: false } } },
|
||||||
"Command Type" to { tx, s -> tx.commandTypes.any { it.simpleName.contains(s, true) } }
|
"Command Type" to { tx, s -> tx.commandTypes.any { it.simpleName.contains(s, true) } }
|
||||||
)
|
)
|
||||||
root.top = searchField.root
|
root.top = searchField.root
|
||||||
@ -170,7 +167,7 @@ class TransactionViewer : CordaView("Transactions") {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ObservableList<List<ObservableValue<NodeInfo?>>>.formatJoinPartyNames(separator: String = "", formatter: Formatter<String>): String {
|
private fun ObservableList<List<ObservableValue<NodeInfo?>>>.formatJoinPartyNames(separator: String = "", formatter: Formatter<X500Name>): String {
|
||||||
return flatten().map {
|
return flatten().map {
|
||||||
it.value?.legalIdentity?.let { formatter.format(it.name) }
|
it.value?.legalIdentity?.let { formatter.format(it.name) }
|
||||||
}.filterNotNull().toSet().joinToString(separator)
|
}.filterNotNull().toSet().joinToString(separator)
|
||||||
@ -294,4 +291,4 @@ private fun calculateTotalEquiv(identity: NodeInfo?,
|
|||||||
.sum() else 0
|
.sum() else 0
|
||||||
|
|
||||||
return AmountDiff.fromLong(outputs.sum() - inputs.sum() - issuedAmount, reportingCurrency)
|
return AmountDiff.fromLong(outputs.sum() - inputs.sum() - issuedAmount, reportingCurrency)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import net.corda.core.contracts.Amount
|
|||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.contracts.withoutIssuer
|
import net.corda.core.contracts.withoutIssuer
|
||||||
import net.corda.core.crypto.AbstractParty
|
import net.corda.core.crypto.AbstractParty
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.explorer.formatters.AmountFormatter
|
import net.corda.explorer.formatters.AmountFormatter
|
||||||
import net.corda.explorer.formatters.PartyNameFormatter
|
import net.corda.explorer.formatters.PartyNameFormatter
|
||||||
import net.corda.explorer.identicon.identicon
|
import net.corda.explorer.identicon.identicon
|
||||||
@ -147,7 +148,7 @@ class CashViewer : CordaView("Cash") {
|
|||||||
*/
|
*/
|
||||||
val searchField = SearchField(cashStates,
|
val searchField = SearchField(cashStates,
|
||||||
"Currency" to { state, text -> state.state.data.amount.token.product.toString().contains(text, true) },
|
"Currency" to { state, text -> state.state.data.amount.token.product.toString().contains(text, true) },
|
||||||
"Issuer" to { state, text -> state.resolveIssuer().value?.name?.contains(text, true) ?: false }
|
"Issuer" to { state, text -> state.resolveIssuer().value?.name?.commonName?.contains(text, true) ?: false }
|
||||||
)
|
)
|
||||||
root.top = hbox(5.0) {
|
root.top = hbox(5.0) {
|
||||||
button("New Transaction", FontAwesomeIconView(FontAwesomeIcon.PLUS)) {
|
button("New Transaction", FontAwesomeIconView(FontAwesomeIcon.PLUS)) {
|
||||||
|
@ -22,6 +22,7 @@ import net.corda.core.contracts.sumOrNull
|
|||||||
import net.corda.core.contracts.withoutIssuer
|
import net.corda.core.contracts.withoutIssuer
|
||||||
import net.corda.core.crypto.AbstractParty
|
import net.corda.core.crypto.AbstractParty
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.flows.FlowException
|
import net.corda.core.flows.FlowException
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
|
@ -216,7 +216,9 @@ fun commandGenerator(partiesToPickFrom: Collection<Party>): Generator<Pair<Comma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val partyGenerator: Generator<Party> = Generator.int().combine(publicKeyGenerator) { n, key -> Party("Party$n", key) }
|
val partyGenerator: Generator<Party> = Generator.int().combine(publicKeyGenerator) { n, key ->
|
||||||
|
Party(X509Utilities.getDevX509Name("Party$n"), key)
|
||||||
|
}
|
||||||
|
|
||||||
fun <A> pickOneOrMaybeNew(from: Collection<A>, generator: Generator<A>): Generator<A> {
|
fun <A> pickOneOrMaybeNew(from: Collection<A>, generator: Generator<A>): Generator<A> {
|
||||||
if (from.isEmpty()) {
|
if (from.isEmpty()) {
|
||||||
|
@ -7,6 +7,8 @@ import com.google.common.util.concurrent.ListeningScheduledExecutorService
|
|||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
|
import net.corda.core.crypto.X509Utilities
|
||||||
|
import net.corda.core.crypto.commonName
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.map
|
import net.corda.core.map
|
||||||
import net.corda.core.random63BitValue
|
import net.corda.core.random63BitValue
|
||||||
@ -32,6 +34,7 @@ import org.apache.activemq.artemis.core.security.CheckType
|
|||||||
import org.apache.activemq.artemis.core.security.Role
|
import org.apache.activemq.artemis.core.security.Role
|
||||||
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl
|
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl
|
||||||
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager
|
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@ -43,7 +46,7 @@ import java.util.concurrent.atomic.AtomicInteger
|
|||||||
*/
|
*/
|
||||||
interface VerifierExposedDSLInterface : DriverDSLExposedInterface {
|
interface VerifierExposedDSLInterface : DriverDSLExposedInterface {
|
||||||
/** Starts a lightweight verification requestor that implements the Node's Verifier API */
|
/** Starts a lightweight verification requestor that implements the Node's Verifier API */
|
||||||
fun startVerificationRequestor(name: String): ListenableFuture<VerificationRequestorHandle>
|
fun startVerificationRequestor(name: X500Name): ListenableFuture<VerificationRequestorHandle>
|
||||||
|
|
||||||
/** Starts an out of process verifier connected to [address] */
|
/** Starts an out of process verifier connected to [address] */
|
||||||
fun startVerifier(address: HostAndPort): ListenableFuture<VerifierHandle>
|
fun startVerifier(address: HostAndPort): ListenableFuture<VerifierHandle>
|
||||||
@ -170,15 +173,15 @@ data class VerifierDriverDSL(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startVerificationRequestor(name: String): ListenableFuture<VerificationRequestorHandle> {
|
override fun startVerificationRequestor(name: X500Name): ListenableFuture<VerificationRequestorHandle> {
|
||||||
val hostAndPort = driverDSL.portAllocation.nextHostAndPort()
|
val hostAndPort = driverDSL.portAllocation.nextHostAndPort()
|
||||||
return driverDSL.executorService.submit<VerificationRequestorHandle> {
|
return driverDSL.executorService.submit<VerificationRequestorHandle> {
|
||||||
startVerificationRequestorInternal(name, hostAndPort)
|
startVerificationRequestorInternal(name, hostAndPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startVerificationRequestorInternal(name: String, hostAndPort: HostAndPort): VerificationRequestorHandle {
|
private fun startVerificationRequestorInternal(name: X500Name, hostAndPort: HostAndPort): VerificationRequestorHandle {
|
||||||
val baseDir = driverDSL.driverDirectory / name
|
val baseDir = driverDSL.driverDirectory / name.commonName
|
||||||
val sslConfig = object : SSLConfiguration {
|
val sslConfig = object : SSLConfiguration {
|
||||||
override val certificatesDirectory = baseDir / "certificates"
|
override val certificatesDirectory = baseDir / "certificates"
|
||||||
override val keyStorePassword: String get() = "cordacadevpass"
|
override val keyStorePassword: String get() = "cordacadevpass"
|
||||||
@ -246,8 +249,8 @@ data class VerifierDriverDSL(
|
|||||||
val id = verifierCount.andIncrement
|
val id = verifierCount.andIncrement
|
||||||
val jdwpPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null
|
val jdwpPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null
|
||||||
val processFuture = driverDSL.executorService.submit<Process> {
|
val processFuture = driverDSL.executorService.submit<Process> {
|
||||||
val verifierName = "verifier$id"
|
val verifierName = X509Utilities.getDevX509Name("verifier$id")
|
||||||
val baseDirectory = driverDSL.driverDirectory / verifierName
|
val baseDirectory = driverDSL.driverDirectory / verifierName.commonName
|
||||||
val config = createConfiguration(baseDirectory, address)
|
val config = createConfiguration(baseDirectory, address)
|
||||||
val configFilename = "verifier.conf"
|
val configFilename = "verifier.conf"
|
||||||
writeConfig(baseDirectory, configFilename, config)
|
writeConfig(baseDirectory, configFilename, config)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user