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:
Ross Nicoll 2017-05-05 15:16:44 +01:00
parent b64e7f51f6
commit 25dbac0f07
80 changed files with 352 additions and 311 deletions

View File

@ -17,6 +17,8 @@ import net.corda.core.serialization.OpaqueBytes
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.i2p.crypto.eddsa.EdDSAPublicKey
import org.bouncycastle.asn1.ASN1InputStream
import org.bouncycastle.asn1.x500.X500Name
import java.math.BigDecimal
import java.security.PublicKey
import java.util.*
@ -32,22 +34,27 @@ object JacksonSupport {
// If you change this API please update the docs in the docsite (json.rst)
interface PartyObjectMapper {
@Deprecated("Use partyFromX500Name instead")
fun partyFromName(partyName: String): Party?
fun partyFromPrincipal(principal: X500Name): Party?
fun partyFromKey(owningKey: PublicKey): Party?
}
class RpcObjectMapper(val rpc: CordaRPCOps, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
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)
}
class IdentityObjectMapper(val identityService: IdentityService, factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
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)
}
class NoPartyObjectMapper(factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) {
override fun partyFromName(partyName: String): Party? = throw UnsupportedOperationException()
override fun partyFromPrincipal(principal: X500Name): Party? = throw UnsupportedOperationException()
override fun partyFromKey(owningKey: PublicKey): Party? = throw UnsupportedOperationException()
}
@ -85,6 +92,10 @@ object JacksonSupport {
// For OpaqueBytes
addDeserializer(OpaqueBytes::class.java, OpaqueBytesDeserializer)
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>() {
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
// TODO this needs to use some industry identifier(s) not just these human readable names
return mapper.partyFromName(parser.text) ?: throw JsonParseException(parser, "Could not find a Party with name ${parser.text}")
val principal = X500Name(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)
}
}
}

View File

@ -37,6 +37,7 @@ import net.corda.testing.expect
import net.corda.testing.expectEvents
import net.corda.testing.node.DriverBasedTest
import net.corda.testing.sequence
import org.bouncycastle.asn1.x500.X500Name
import org.junit.Test
import rx.Observable
@ -54,7 +55,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
lateinit var transactions: Observable<SignedTransaction>
lateinit var vaultUpdates: Observable<Vault.Update>
lateinit var networkMapUpdates: Observable<NetworkMapCache.MapChange>
lateinit var newNode: (String) -> NodeInfo
lateinit var newNode: (X500Name) -> NodeInfo
override fun setup() = driver {
val cashUser = User("user1", "test", permissions = setOf(

View File

@ -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.InVMConnectorFactory
import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ
import org.bouncycastle.asn1.x500.X500Name
import org.junit.After
import org.junit.Before
import java.util.*
@ -75,7 +74,7 @@ abstract class AbstractClientRPCTest {
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) {
val msg = serverSession.createMessage(false).apply {
writeBodyBufferBytes(data.bytes)
@ -100,4 +99,4 @@ abstract class AbstractClientRPCTest {
} catch (e: Exception) {
}
}
}
}

View File

@ -3,6 +3,7 @@ package net.corda.core.crypto
import net.corda.core.contracts.PartyAndReference
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.OpaqueBytes
import org.bouncycastle.asn1.x500.X500Name
import java.security.PublicKey
/**
@ -16,7 +17,7 @@ abstract class AbstractParty(val owningKey: PublicKey) {
override fun hashCode(): Int = owningKey.hashCode()
abstract fun toAnonymous(): AnonymousParty
abstract fun nameOrNull(): String?
abstract fun nameOrNull(): X500Name?
abstract fun ref(bytes: OpaqueBytes): PartyAndReference
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))

View File

@ -2,6 +2,7 @@ package net.corda.core.crypto
import net.corda.core.contracts.PartyAndReference
import net.corda.core.serialization.OpaqueBytes
import org.bouncycastle.asn1.x500.X500Name
import java.security.PublicKey
/**
@ -13,7 +14,7 @@ class AnonymousParty(owningKey: PublicKey) : AbstractParty(owningKey) {
// can put in the key and actual name
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 toAnonymous() = this

View File

@ -12,7 +12,8 @@ import java.security.PublicKey
* 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.
* 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,
* 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
*/
class Party(val name: String, owningKey: PublicKey) : AbstractParty(owningKey) {
constructor(name: X500Name, owningKey: PublicKey) : this(name.toString(), owningKey)
class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) {
override fun toAnonymous(): AnonymousParty = AnonymousParty(owningKey)
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)
}
}

View File

@ -109,9 +109,8 @@ object X509Utilities {
/**
* 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 {
// Check that we haven't been accidentally given a full X500 distinguished name
require(!commonName.startsWith("CN=")) { "Provided common name must not start \"CN=\"" }
val nameBuilder = X500NameBuilder(BCStyle.INSTANCE)
nameBuilder.addRDN(BCStyle.CN, commonName)
nameBuilder.addRDN(BCStyle.O, "R3")
@ -271,16 +270,6 @@ object X509Utilities {
*/
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].
* @param subject the cert Subject will be populated with the domain string
@ -324,18 +313,6 @@ object X509Utilities {
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.
* @param subject subject of the generated certificate.
@ -547,10 +524,14 @@ object X509Utilities {
storePassword: String,
keyPassword: String,
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 {
val rootCA = createSelfSignedCACert(getDevX509Name("Corda Node Root CA"))
val intermediateCA = createIntermediateCert(getDevX509Name("Corda Node Intermediate CA"), rootCA)
val rootCA = createSelfSignedCACert(rootCaName)
val intermediateCA = createIntermediateCert(intermediateCaName, rootCA)
val keyPass = keyPassword.toCharArray()
val keyStore = loadOrCreateKeyStore(keyStoreFilePath, storePassword)
@ -591,24 +572,6 @@ object X509Utilities {
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
* @param keyStoreFilePath KeyStore path to save output to

View File

@ -236,6 +236,7 @@ interface CordaRPCOps : RPCOps {
/**
* Returns the [Party] with the given name as it's [Party.name]
*/
@Deprecated("Use partyFromX500Name instead")
fun partyFromName(name: String): Party?
/**

View File

@ -3,8 +3,8 @@ package net.corda.core.node.services
import net.corda.core.contracts.PartyAndReference
import net.corda.core.crypto.AnonymousParty
import net.corda.core.crypto.Party
import java.security.PublicKey
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
@ -25,6 +25,7 @@ interface IdentityService {
// but for now this is not supported.
fun partyFromKey(key: PublicKey): Party?
@Deprecated("Use partyFromX500Name")
fun partyFromName(name: String): Party?
fun partyFromX500Name(principal: X500Name): Party?

View File

@ -6,6 +6,7 @@ import net.corda.core.crypto.Party
import net.corda.core.node.NodeInfo
import net.corda.core.randomOrNull
import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.asn1.x500.X500Name
import rx.Observable
import java.security.PublicKey
@ -62,7 +63,7 @@ interface NetworkMapCache {
fun getRecommended(type: ServiceType, contract: Contract, vararg party: Party): NodeInfo? = getNodesWithService(type).firstOrNull()
/** 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
@ -82,9 +83,9 @@ interface NetworkMapCache {
fun getPartyInfo(party: Party): PartyInfo?
/** Gets a notary identity by the given name. */
fun getNotary(name: String): Party? {
fun getNotary(principal: X500Name): Party? {
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
}

View File

@ -11,15 +11,15 @@ import org.bouncycastle.asn1.x500.X500Name
* grouping identifier for nodes collectively running a distributed service.
*/
@CordaSerializable
data class ServiceInfo(val type: ServiceType, val name: String? = null) {
constructor(type: ServiceType, name: X500Name?) : this(type, name?.toString())
data class ServiceInfo(val type: ServiceType, val name: X500Name? = null) {
companion object {
fun parse(encoded: String): ServiceInfo {
val parts = encoded.split("|")
require(parts.size in 1..2) { "Invalid number of elements found" }
val type = ServiceType.parse(parts[0])
val name = parts.getOrNull(1)
return ServiceInfo(type, name)
val principal = name?.let { X500Name(it) }
return ServiceInfo(type, principal)
}
}

View File

@ -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.serialization.CordaSerializable
import net.corda.core.serialization.OpaqueBytes
import org.bouncycastle.asn1.x500.X500Name
import java.time.Instant
import java.util.*
@ -26,10 +27,10 @@ sealed class QueryCriteria {
val status: Vault.StateStatus = Vault.StateStatus.UNCONSUMED,
val stateRefs: List<StateRef>? = null,
val contractStateTypes: Set<Class<out ContractState>>? = null,
val notaryName: List<String>? = null,
val notaryName: List<X500Name>? = null,
val includeSoftlockedStates: Boolean? = true,
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]
@ -38,7 +39,7 @@ sealed class QueryCriteria {
val linearId: List<UniqueIdentifier>? = null,
val latestOnly: Boolean? = true,
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]
@ -48,11 +49,11 @@ sealed class QueryCriteria {
* [Commodity] as used in [CommodityContract] state
*/
data class FungibleAssetQueryCriteria @JvmOverloads constructor(
val ownerIdentity: List<String>? = null,
val ownerIdentity: List<X500Name>? = null,
val quantity: Logical<*,Long>? = null,
val tokenType: List<Class<out Any>>? = null,
val tokenValue: List<String>? = null,
val issuerPartyName: List<String>? = null,
val issuerPartyName: List<X500Name>? = null,
val issuerRef: List<OpaqueBytes>? = null,
val exitKeyIdentity: List<String>? = null) : QueryCriteria()

View File

@ -2,6 +2,7 @@ package net.corda.core.crypto
import net.corda.core.div
import net.corda.testing.MEGA_CORP
import net.corda.testing.getTestX509Name
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.GeneralName
import org.junit.Rule
@ -31,7 +32,7 @@ class X509UtilitiesTest {
@Test
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
assertEquals(caCertAndKey.certificate.issuerDN, caCertAndKey.certificate.subjectDN) //self-signed
caCertAndKey.certificate.checkValidity(Date()) // throws on verification problems
@ -43,7 +44,7 @@ class X509UtilitiesTest {
@Test
fun `load and save a PEM file certificate`() {
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)
val readCertificate = X509Utilities.loadCertificateFromPEMFile(tmpCertificateFile)
assertEquals(caCertAndKey.certificate, readCertificate)
@ -51,8 +52,8 @@ class X509UtilitiesTest {
@Test
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 subjectDN = X500Name("CN=Server Cert,OU=Corda QA Department,O=R3 CEV,L=New York,C=US")
val caCertAndKey = X509Utilities.createSelfSignedCACert(getTestX509Name("Test CA Cert"))
val subjectDN = getTestX509Name("Server Cert")
val keyPair = X509Utilities.generateECDSAKeyPairForSSL()
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
@ -139,7 +140,7 @@ class X509UtilitiesTest {
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
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
val serverKeyStore = X509Utilities.loadKeyStore(tmpServerKeyStore, "serverstorepass")
@ -148,7 +149,7 @@ class X509UtilitiesTest {
serverCertAndKey.certificate.checkValidity(Date())
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
val testData = "123456".toByteArray()
@ -176,7 +177,7 @@ class X509UtilitiesTest {
"trustpass")
// 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 context = SSLContext.getInstance("TLS")
@ -249,7 +250,7 @@ class X509UtilitiesTest {
val peerChain = clientSocket.session.peerCertificates
val peerX500Principal = (peerChain[0] as X509Certificate).subjectX500Principal
val x500name = X500Name(peerX500Principal.name)
assertEquals(X500Name(MEGA_CORP.name), x500name)
assertEquals(MEGA_CORP.name, x500name)
val output = DataOutputStream(clientSocket.outputStream)

View File

@ -3,6 +3,7 @@ package net.corda.core.node
import net.corda.core.crypto.X509Utilities
import net.corda.core.node.services.ServiceInfo
import net.corda.core.node.services.ServiceType
import net.corda.testing.getTestX509Name
import org.bouncycastle.asn1.x500.X500Name
import org.junit.Test
import kotlin.test.assertEquals
@ -10,7 +11,7 @@ import kotlin.test.assertFailsWith
class ServiceInfoTests {
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
fun `type and name encodes correctly`() {

View File

@ -2,12 +2,12 @@ package net.corda.core.testing
import com.pholser.junit.quickcheck.generator.GenerationStatus
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.random.SourceOfRandomness
import net.corda.core.contracts.*
import net.corda.core.crypto.*
import net.corda.core.serialization.OpaqueBytes
import net.corda.testing.getTestX509Name
import org.bouncycastle.asn1.x500.X500Name
import java.nio.ByteBuffer
import java.nio.charset.Charset
@ -51,7 +51,7 @@ class AnonymousPartyGenerator : Generator<AnonymousParty>(AnonymousParty::class.
class PartyGenerator : Generator<Party>(Party::class.java) {
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) {
appendProperNoun(cn, random, status).append(" ")
}
return X509Utilities.getDevX509Name(cn.trim().toString())
return getTestX509Name(cn.trim().toString())
}
}

View File

@ -1,6 +1,7 @@
package net.corda.contracts.universal
import net.corda.core.crypto.Party
import net.corda.core.crypto.commonName
import java.math.BigDecimal
import java.security.PublicKey
import java.time.Instant
@ -46,7 +47,7 @@ private class PrettyPrint(arr : Arrangement) {
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()) {
s, i -> s + i.first().toUpperCase() + i.drop(1)
@ -64,7 +65,7 @@ private class PrettyPrint(arr : Arrangement) {
init {
parties.forEach {
println( "val ${createPartyName(it)} = Party(\"${it.name}\", \"${it.owningKey}\")" )
println( "val ${createPartyName(it)} = Party(\"${it.name.commonName}\", \"${it.owningKey}\")" )
}
}

View File

@ -5,20 +5,21 @@ import net.corda.nodeapi.config.SSLConfiguration
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.TransportConstants
import org.bouncycastle.asn1.x500.X500Name
import java.nio.file.FileSystems
import java.nio.file.Path
sealed class ConnectionDirection {
data class Inbound(val acceptorFactoryClassName: String) : ConnectionDirection()
data class Outbound(
val expectedCommonName: String? = null,
val expectedCommonName: X500Name? = null,
val connectorFactoryClassName: String = NettyConnectorFactory::class.java.name
) : ConnectionDirection()
}
class ArtemisTcpTransport {
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.
// 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_PROTOCOLS_PROP_NAME to "TLSv1.2",
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)
}

View File

@ -98,6 +98,7 @@ private fun Config.getCollectionValue(path: String, type: KType): Collection<Any
HostAndPort::class -> getStringList(path).map(HostAndPort::fromString)
Path::class -> getStringList(path).map { Paths.get(it) }
URL::class -> getStringList(path).map(::URL)
X500Name::class -> getStringList(path).map(::X500Name)
Properties::class -> getConfigList(path).map(Config::toProperties)
else -> if (elementClass.java.isEnum) {
getStringList(path).map { parseEnum(elementClass.java, it) }

View File

@ -6,7 +6,9 @@ import com.typesafe.config.ConfigFactory.empty
import com.typesafe.config.ConfigRenderOptions.defaults
import com.typesafe.config.ConfigValueFactory
import net.corda.core.div
import net.corda.testing.getTestX509Name
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
import org.junit.Test
import java.net.URL
import java.nio.file.Path
@ -15,6 +17,7 @@ import java.time.Instant
import java.time.LocalDate
import java.util.*
import kotlin.reflect.full.primaryConstructor
import kotlin.test.assertEquals
class ConfigParsingTest {
@Test
@ -109,6 +112,11 @@ class ConfigParsingTest {
assertThat(empty().parseAs<StringSetData>().values).isEmpty()
}
@Test
fun x500Name() {
testPropertyType<X500NameData, X500NameListData, X500Name>(getTestX509Name("Mock Node"), getTestX509Name("Mock Node 2"), valuesToString = true)
}
@Test
fun `multi property data class`() {
val data = config(
@ -223,6 +231,8 @@ class ConfigParsingTest {
data class PathListData(override val values: List<Path>) : ListData<Path>
data class URLData(override val value: URL) : SingleData<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 PropertiesListData(override val values: List<Properties>) : ListData<Properties>
data class MultiPropertyData(val i: Int, val b: Boolean, val l: List<String>)

View File

@ -292,7 +292,7 @@ class VaultSchemaTest {
stateStatus = Vault.StateStatus.UNCONSUMED
contractStateClassName = state.data.javaClass.name
contractState = state.serialize().bytes
notaryName = state.notary.name
notaryName = state.notary.name.toString()
notaryKey = state.notary.owningKey.toBase58String()
recordedTime = Instant.now()
}

View File

@ -5,6 +5,7 @@ import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionType
import net.corda.core.crypto.Party
import net.corda.core.crypto.commonName
import net.corda.core.div
import net.corda.core.getOrThrow
import net.corda.core.node.services.ServiceInfo
@ -19,6 +20,9 @@ import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.node.utilities.transaction
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 java.security.KeyPair
import java.util.*
@ -27,7 +31,19 @@ import kotlin.test.assertFailsWith
class BFTNotaryServiceTests : NodeBasedTest() {
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
@ -73,13 +89,13 @@ class BFTNotaryServiceTests : NodeBasedTest() {
}
}
private fun startBFTNotaryCluster(notaryName: String,
private fun startBFTNotaryCluster(notaryName: X500Name,
clusterSize: Int,
serviceType: ServiceType): List<Node> {
require(clusterSize > 0)
val quorum = (2 * clusterSize + 1) / 3
ServiceIdentityGenerator.generateToDisk(
(0 until clusterSize).map { tempFolder.root.toPath() / "$notaryName-$it" },
(0 until clusterSize).map { tempFolder.root.toPath() / "${notaryName.commonName}-$it" },
serviceType.id,
notaryName,
quorum)
@ -87,7 +103,7 @@ class BFTNotaryServiceTests : NodeBasedTest() {
val serviceInfo = ServiceInfo(serviceType, notaryName)
val nodes = (0 until clusterSize).map {
startNode(
"$notaryName-$it",
buildNodeName(it, notaryName),
advertisedServices = setOf(serviceInfo),
configOverrides = mapOf("notaryNodeId" to it)
).getOrThrow()

View File

@ -15,6 +15,7 @@ import net.corda.flows.NotaryFlow
import net.corda.node.internal.AbstractNode
import net.corda.node.utilities.transaction
import net.corda.testing.node.NodeBasedTest
import org.bouncycastle.asn1.x500.X500Name
import org.junit.Test
import java.security.KeyPair
import java.util.*
@ -22,7 +23,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
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
fun `detect double spend`() {

View File

@ -5,6 +5,8 @@ import com.google.common.util.concurrent.Futures
import net.corda.core.crypto.Party
import net.corda.core.flows.FlowLogic
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.testing.node.NodeBasedTest
import org.assertj.core.api.Assertions.assertThat
@ -14,8 +16,8 @@ class FlowVersioningTest : NodeBasedTest() {
@Test
fun `core flows receive platform version of initiator`() {
val (alice, bob) = Futures.allAsList(
startNode("Alice", platformVersion = 2),
startNode("Bob", platformVersion = 3)).getOrThrow()
startNode(ALICE.name, platformVersion = 2),
startNode(BOB.name, platformVersion = 3)).getOrThrow()
bob.installCoreFlow(ClientFlow::class, ::SendBackPlatformVersionFlow)
val resultFuture = alice.services.startFlow(ClientFlow(bob.info.legalIdentity)).resultFuture
assertThat(resultFuture.getOrThrow()).isEqualTo(2)

View File

@ -4,6 +4,7 @@ import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import net.corda.core.*
import net.corda.core.crypto.X509Utilities
import net.corda.core.crypto.commonName
import net.corda.core.messaging.MessageRecipients
import net.corda.core.messaging.SingleMessageRecipient
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.utilities.ServiceIdentityGenerator
import net.corda.testing.freeLocalHostAndPort
import net.corda.testing.getTestX509Name
import net.corda.testing.node.NodeBasedTest
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
@ -30,8 +32,8 @@ import java.util.concurrent.atomic.AtomicInteger
class P2PMessagingTest : NodeBasedTest() {
private companion object {
val DISTRIBUTED_SERVICE_NAME = X509Utilities.getDevX509Name("DistributedService")
val SERVICE_2_NAME = X509Utilities.getDevX509Name("Service Node 2")
val DISTRIBUTED_SERVICE_NAME = getTestX509Name("DistributedService")
val SERVICE_2_NAME = getTestX509Name("Service Node 2")
}
@Test
@ -65,7 +67,7 @@ class P2PMessagingTest : NodeBasedTest() {
val root = tempFolder.root.toPath()
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,
DISTRIBUTED_SERVICE_NAME)
@ -96,7 +98,7 @@ class P2PMessagingTest : NodeBasedTest() {
@Test
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 serviceAddress = alice.services.networkMapCache.run {
alice.net.getAddressOfParty(getPartyInfo(getAnyNotary()!!)!!)
@ -121,7 +123,7 @@ class P2PMessagingTest : NodeBasedTest() {
@Test
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 serviceAddress = alice.services.networkMapCache.run {
alice.net.getAddressOfParty(getPartyInfo(getAnyNotary()!!)!!)
@ -194,7 +196,7 @@ class P2PMessagingTest : NodeBasedTest() {
node.respondWith(node.info)
}
val serviceAddress = originatingNode.services.networkMapCache.run {
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName.toString())!!)!!)
originatingNode.net.getAddressOfParty(getPartyInfo(getNotary(serviceName)!!)!!)
}
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

View File

@ -2,6 +2,7 @@ package net.corda.services.messaging
import com.google.common.util.concurrent.ListenableFuture
import net.corda.core.crypto.Party
import net.corda.core.crypto.X509Utilities
import net.corda.core.crypto.commonName
import net.corda.core.div
import net.corda.core.getOrThrow
@ -33,22 +34,22 @@ class P2PSecurityTest : NodeBasedTest() {
@Test
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(
"networkMapService" to mapOf(
"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
assertThatThrownBy { node.getOrThrow() }.hasMessageContaining(incorrectNetworkMapName)
assertThatThrownBy { node.getOrThrow() }.hasMessageContaining(incorrectNetworkMapName.toString())
}
@Test
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
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
// to the attacker as the TLS CN will not match the legal name it has just provided
assertThatExceptionOfType(TimeoutException::class.java).isThrownBy {

View File

@ -63,23 +63,6 @@ private val log: Logger = loggerFor<DriverDSL>()
* This is the interface that's exposed to DSL users.
*/
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.
*
@ -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.
*/
fun startNotaryCluster(
notaryName: String,
notaryName: X500Name,
clusterSize: Int = 3,
type: ServiceType = RaftValidatingNotaryService.type,
verifierType: VerifierType = VerifierType.InMemory,
@ -444,25 +427,13 @@ class DriverDSL(
verifierType: VerifierType,
customOverrides: Map<String, Any?>
): 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 rpcAddress = portAllocation.nextHostAndPort()
val webAddress = portAllocation.nextHostAndPort()
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val name = providedName.toString() ?: X509Utilities.getDevX509Name("${pickA(name).commonName}-${p2pAddress.port}").toString()
val commonName = try {
X500Name(name).commonName
} catch(ex: IllegalArgumentException) {
name
}
val baseDirectory = driverDirectory / commonName
// TODO: Derive name from the full picked name, don't just wrap the common name
val name = providedName ?: X509Utilities.getDevX509Name("${pickA(name).commonName}-${p2pAddress.port}")
val baseDirectory = driverDirectory / name.commonName
val configOverrides = mapOf(
"myLegalName" to name.toString(),
"p2pAddress" to p2pAddress.toString(),
@ -471,7 +442,7 @@ class DriverDSL(
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
"networkMapService" to mapOf(
"address" to networkMapAddress.toString(),
"legalName" to networkMapLegalName
"legalName" to networkMapLegalName.toString()
),
"useTestClock" to useTestClock,
"rpcUsers" to rpcUsers.map {
@ -503,14 +474,23 @@ class DriverDSL(
}
override fun startNotaryCluster(
notaryName: String,
notaryName: X500Name,
clusterSize: Int,
type: ServiceType,
verifierType: VerifierType,
rpcUsers: List<User>
): ListenableFuture<Pair<Party, List<NodeHandle>>> {
val nodeNames = (1..clusterSize).map { "Notary Node $it" }
val paths = nodeNames.map { driverDirectory / it }
val nodeNames = (1..clusterSize).map {
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)
val serviceInfo = ServiceInfo(type, notaryName)
@ -567,17 +547,12 @@ class DriverDSL(
override fun startNetworkMapService() {
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val apiAddress = portAllocation.nextHostAndPort().toString()
val nodeDirectoryName = try {
X500Name(networkMapLegalName).commonName
} catch(ex: IllegalArgumentException) {
networkMapLegalName
}
val baseDirectory = driverDirectory / nodeDirectoryName
val baseDirectory = driverDirectory / networkMapLegalName.commonName
val config = ConfigHelper.loadConfig(
baseDirectory = baseDirectory,
allowMissingConfig = true,
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
// node port numbers to be shifted, so all demos and docs need to be updated accordingly.
"webAddress" to apiAddress,
@ -593,9 +568,9 @@ class DriverDSL(
companion object {
val name = arrayOf(
X500Name(ALICE.name),
X500Name(BOB.name),
X500Name(DUMMY_BANK_A.name)
ALICE.name,
BOB.name,
DUMMY_BANK_A.name
)
fun <A> pickA(array: Array<A>): A = array[Math.abs(Random().nextInt()) % array.size]

View File

@ -58,6 +58,7 @@ import net.corda.node.utilities.AffinityExecutor
import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import org.apache.activemq.artemis.utils.ReusableLatch
import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.slf4j.Logger
import java.io.IOException
@ -338,7 +339,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
protected open fun makeServiceEntries(): List<ServiceEntry> {
return advertisedServices.map {
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
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 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
// 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
@ -566,13 +567,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
// the legal name is actually validated in some way.
val privKeyFile = dir / privateKeyFileName
val pubIdentityFile = dir / publicKeyFileName
val identityName = serviceName ?: configuration.myLegalName.toString()
val identityPrincipal: X500Name = serviceName ?: configuration.myLegalName
val identityAndKey = if (!privKeyFile.exists()) {
log.info("Identity key not found, generating fresh key!")
val keyPair: KeyPair = generateKeyPair()
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
// wrong type by mistake.
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
// things up for us.
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:" +
"$identityName vs ${myIdentity.name}")
"$identityPrincipal vs ${myIdentity.name}")
// Load the private key.
val keyPair = privKeyFile.readAll().deserialize<KeyPair>()
Pair(myIdentity, keyPair)

View File

@ -173,6 +173,7 @@ class CordaRPCOpsImpl(
override fun waitUntilRegisteredWithNetworkMap() = services.networkMapCache.mapServiceRegistered
override fun partyFromKey(key: PublicKey) = services.identityService.partyFromKey(key)
@Deprecated("Use partyFromX500Name instead")
override fun partyFromName(name: String) = services.identityService.partyFromName(name)
override fun partyFromX500Name(x500Name: X500Name)= services.identityService.partyFromX500Name(x500Name)

View File

@ -30,6 +30,7 @@ import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.utilities.AddressUtils
import net.corda.node.utilities.AffinityExecutor
import net.corda.nodeapi.ArtemisMessagingComponent.NetworkMapAddress
import org.bouncycastle.asn1.x500.X500Name
import org.slf4j.Logger
import java.io.RandomAccessFile
import java.lang.management.ManagementFactory
@ -317,4 +318,4 @@ class Node(override val configuration: FullNodeConfiguration,
class ConfigurationException(message: String) : Exception(message)
data class NetworkMapInfo(val address: HostAndPort, val legalName: String)
data class NetworkMapInfo(val address: HostAndPort, val legalName: X500Name)

View File

@ -7,8 +7,8 @@ import net.corda.core.node.services.IdentityService
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.trace
import java.security.PublicKey
import org.bouncycastle.asn1.x500.X500Name
import java.security.PublicKey
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import javax.annotation.concurrent.ThreadSafe
@ -23,20 +23,21 @@ class InMemoryIdentityService : SingletonSerializeAsToken(), IdentityService {
}
private val keyToParties = ConcurrentHashMap<PublicKey, Party>()
private val nameToParties = ConcurrentHashMap<String, Party>()
private val principalToParties = ConcurrentHashMap<X500Name, Party>()
override fun registerIdentity(party: Party) {
log.trace { "Registering identity $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
override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values)
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
override fun partyFromName(name: String): Party? = nameToParties[name]
override fun partyFromX500Name(principal: X500Name): Party? = nameToParties[principal.toString()]
@Deprecated("Use partyFromX500Name")
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(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
}

View File

@ -238,7 +238,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
.loadCertificateFromKeyStore(config.keyStoreFile, config.keyStorePassword, CORDA_CLIENT_CA)
val ourSubjectDN = X500Name(ourCertificate.subjectDN.name)
// This is a sanity check and should not fail unless things have been misconfigured
require(ourSubjectDN.commonName == config.myLegalName.commonName) {
require(ourSubjectDN == config.myLegalName) {
"Legal name does not match with our subject CN: $ourSubjectDN"
}
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)
}
@ -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
* P2P address.
*/
private fun deployBridge(queueName: String, target: HostAndPort, legalName: String) {
private fun deployBridge(queueName: String, target: HostAndPort, legalName: X500Name) {
val connectionDirection = ConnectionDirection.Outbound(
connectorFactoryClassName = VerifyingNettyConnectorFactory::class.java.name,
expectedCommonName = legalName
@ -401,7 +401,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
internal fun hostVerificationFail(peerLegalName: X500Name, expectedLegalName: X500Name) {
log.error("Peer has wrong CN - expected $expectedLegalName but got $peerLegalName. This is either a fatal " +
"misconfiguration by the remote peer or an SSL man-in-the-middle attack!")
if (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!
_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
internal fun onTcpConnection(peerLegalName: X500Name) {
if (peerLegalName.toString() == config.networkMapService?.legalName) {
if (peerLegalName == config.networkMapService?.legalName) {
_networkMapConnectionFuture!!.set(Unit)
}
}
@ -437,14 +437,12 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
protocolManager: ClientProtocolManager?) :
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
private val server = configuration?.get(ArtemisMessagingServer::class.java.name) as? ArtemisMessagingServer
private val expectedCommonName = (configuration?.get(ArtemisTcpTransport.VERIFY_PEER_COMMON_NAME) as? String)?.let {
X500Name(it)
}
private val expecteLegalName: X500Name? = configuration?.get(ArtemisTcpTransport.VERIFY_PEER_LEGAL_NAME) as X500Name?
override fun createConnection(): Connection? {
val connection = super.createConnection() as NettyConnection?
if (connection != null && expectedCommonName != null) {
val peerLegalName = connection
if (connection != null && expecteLegalName != null) {
val peerLegalName: X500Name = connection
.channel
.pipeline()
.get(SslHandler::class.java)
@ -453,10 +451,9 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
.peerPrincipal
.name
.let(::X500Name)
// TODO Verify on the entire principle (subject)
if (peerLegalName.commonName != expectedCommonName.commonName) {
if (peerLegalName != expecteLegalName) {
connection.close()
server!!.hostVerificationFail(peerLegalName, expectedCommonName)
server!!.hostVerificationFail(peerLegalName, expecteLegalName)
return null // Artemis will keep trying to reconnect until it's told otherwise
} else {
server!!.onTcpConnection(peerLegalName)

View File

@ -5,6 +5,7 @@ import net.corda.core.crypto.Party
import net.corda.core.messaging.SingleMessageRecipient
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.utilities.*
import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.statements.InsertStatement
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 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 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
}

View File

@ -281,8 +281,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
private fun onSessionMessage(message: ReceivedMessage) {
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.commonName)?.legalIdentity
val sender = serviceHub.networkMapCache.getNodeByLegalName(message.peer)?.legalIdentity
if (sender != null) {
when (sessionMessage) {
is ExistingSessionMessage -> onExistingSessionMessage(sessionMessage, sender)

View File

@ -54,7 +54,7 @@ class PersistentUniquenessProvider : UniquenessProvider, SingletonSerializeAsTok
finalizables: MutableList<() -> Unit>) {
insert[table.consumingTxHash] = entry.value.id
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
}
})

View File

@ -91,7 +91,7 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P
stateStatus = Vault.StateStatus.UNCONSUMED
contractStateClassName = it.value.state.data.javaClass.name
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()
recordedTime = services.clock.instant()
}

View File

@ -6,6 +6,7 @@ import net.corda.core.crypto.generateKeyPair
import net.corda.core.serialization.serialize
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.trace
import org.bouncycastle.asn1.x500.X500Name
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
@ -23,7 +24,7 @@ object ServiceIdentityGenerator {
* @param serviceName The legal name of the distributed service.
* @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()}" }
val keyPairs = (1..dirs.size).map { generateKeyPair() }
@ -43,7 +44,7 @@ object ServiceIdentityGenerator {
fun main(args: Array<String>) {
val dirs = args[0].split("|").map { Paths.get(it) }
val serviceId = args[1]
val serviceName = args[2]
val serviceName = X500Name(args[2])
val quorumSize = args.getOrNull(3)?.toInt() ?: 1
println("Generating service identity for \"$serviceName\"")

View File

@ -12,6 +12,7 @@ import net.corda.core.serialization.*;
import net.corda.core.transactions.*;
import net.corda.node.services.vault.schemas.*;
import net.corda.testing.node.*;
import org.bouncycastle.asn1.x500.X500Name;
import org.jetbrains.annotations.*;
import org.jetbrains.exposed.sql.*;
import org.junit.*;
@ -129,7 +130,7 @@ public class VaultQueryJavaTests {
QueryCriteria vaultCriteria = new VaultQueryCriteria(status, null, contractStateTypes);
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 compositeCriteria = and(dealCriteriaAll, vaultCriteria);
@ -198,7 +199,7 @@ public class VaultQueryJavaTests {
QueryCriteria vaultCriteria = new VaultQueryCriteria(Vault.StateStatus.UNCONSUMED, null, contractStateTypes);
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 compositeCriteria = and(dealCriteriaAll, vaultCriteria);

View File

@ -29,7 +29,7 @@ class InteractiveShellTest {
constructor(b: Int, c: String) : this(b.toString() + c)
constructor(amount: Amount<Currency>) : this(amount.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
}
@ -67,7 +67,7 @@ class InteractiveShellTest {
fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "")
@Test
fun party() = check("party: \"$someCorpLegalName\"", someCorpLegalName)
fun party() = check("party: \"$someCorpLegalName\"", someCorpLegalName.toString())
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> {

View File

@ -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
// 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 ...
return net.createNode(networkMapAddr, -1, object : MockNetwork.Factory {
override fun create(config: NodeConfiguration,

View File

@ -12,7 +12,7 @@ class FullNodeConfigurationTest {
@Test
fun `Artemis special characters not permitted in RPC usernames`() {
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())))
}

View File

@ -130,7 +130,7 @@ class RequeryConfigurationTest {
stateStatus = Vault.StateStatus.UNCONSUMED
contractStateClassName = DummyContract.SingleOwnerState::class.java.name
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()
recordedTime = Instant.now()
}

View File

@ -22,6 +22,7 @@ import net.corda.testing.node.MockKeyManagementService
import net.corda.testing.node.TestClock
import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.junit.After
import org.junit.Before
@ -79,7 +80,8 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
database.transaction {
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 {
override val vaultService: VaultService = NodeVaultService(this, dataSourceProps)
override val testReference = this@NodeSchedulerServiceTest

View File

@ -72,7 +72,7 @@ class ArtemisMessagingTests {
userService = RPCUserServiceImpl(emptyList())
config = TestNodeConfiguration(
baseDirectory = baseDirectory,
myLegalName = X500Name(ALICE.name),
myLegalName = ALICE.name,
networkMapService = null)
LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties())

View File

@ -29,6 +29,7 @@ import net.corda.node.utilities.AddOrRemove.REMOVE
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
import org.eclipse.jetty.util.BlockingArrayQueue
import org.junit.After
import org.junit.Before
@ -43,7 +44,7 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
lateinit var alice: MockNode
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
@ -246,14 +247,14 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
network.runNetwork()
}
private fun addNewNodeToNetworkMap(legalName: String): MockNode {
private fun addNewNodeToNetworkMap(legalName: X500Name): MockNode {
val node = network.createNode(networkMapAddress = mapServiceNode.info.address, legalName = legalName)
network.runNetwork()
lastSerial = System.currentTimeMillis()
return node
}
private fun newNodeSeparateFromNetworkMap(legalName: String): MockNode {
private fun newNodeSeparateFromNetworkMap(legalName: X500Name): MockNode {
return network.createNode(legalName = legalName, nodeFactory = NoNMSNodeFactory)
}

View File

@ -46,7 +46,7 @@ class InMemoryIdentityServiceTests {
@Test
fun `get identity by name with no registered identities`() {
val service = InMemoryIdentityService()
assertNull(service.partyFromName(ALICE.name))
assertNull(service.partyFromX500Name(ALICE.name))
}
@Test
@ -54,8 +54,8 @@ class InMemoryIdentityServiceTests {
val service = InMemoryIdentityService()
val identities = listOf("Node A", "Node B", "Node C")
.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 { assertEquals(it, service.partyFromName(it.name)) }
identities.forEach { assertEquals(it, service.partyFromX500Name(it.name)) }
}
}

View File

@ -33,6 +33,7 @@ import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.node.utilities.transaction
import net.corda.testing.expect
import net.corda.testing.expectEvents
import net.corda.testing.getTestX509Name
import net.corda.testing.initiateSingleShotFlow
import net.corda.testing.node.InMemoryMessagingNetwork
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.assertThatThrownBy
import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType
import org.bouncycastle.asn1.x500.X500Name
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -74,7 +76,7 @@ class StateMachineManagerTests {
node1 = nodes.first
node2 = nodes.second
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))
// Note that these notaries don't operate correctly as they don't share their state. They are only used for testing
// service addressing.

View File

@ -184,7 +184,7 @@ class VaultQueryTests {
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
fun `unconsumed states by notary`() {

View File

@ -8,6 +8,7 @@ import net.corda.core.crypto.X509Utilities
import net.corda.core.exists
import net.corda.core.utilities.ALICE
import net.corda.testing.TestNodeConfiguration
import net.corda.testing.getTestX509Name
import org.bouncycastle.asn1.x500.X500Name
import org.junit.Rule
import org.junit.Test
@ -28,7 +29,7 @@ class NetworkRegistrationHelperTest {
val identities = listOf("CORDA_CLIENT_CA",
"CORDA_INTERMEDIATE_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 }
.toTypedArray()
@ -39,7 +40,7 @@ class NetworkRegistrationHelperTest {
val config = TestNodeConfiguration(
baseDirectory = tempFolder.root.toPath(),
myLegalName = X500Name(ALICE.name),
myLegalName = ALICE.name,
networkMapService = null)
assertFalse(config.keyStoreFile.exists())

View File

@ -72,7 +72,7 @@ fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K.
fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) {
// 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
if (!rpc.attachmentExists(hash)) {

View File

@ -8,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo
import net.corda.node.driver.driver
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.BOC
import net.corda.testing.http.HttpUtils
import org.bouncycastle.asn1.x500.X500Name
import org.junit.Test
import kotlin.test.assertTrue
@ -21,7 +22,7 @@ class BankOfCordaHttpAPITest {
startNode(BIGCORP_LEGAL_NAME)
).getOrThrow()
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)
}
}

View File

@ -67,7 +67,7 @@ private class BankOfCordaDriver {
}, isDebug = true)
} else {
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) {
Role.ISSUE_CASH_RPC -> {
println("Requesting Cash via RPC ...")

View File

@ -36,9 +36,9 @@ class BankOfCordaClientApi(val hostAndPort: HostAndPort) {
val proxy = client.proxy()
// 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")
val issuerBankParty = proxy.partyFromName(params.issuerBankName)
val issuerBankParty = proxy.partyFromX500Name(params.issuerBankName)
?: throw Exception("Unable to locate ${params.issuerBankName} in Network Map Service")
val amount = Amount(params.amount, currency(params.currency))

View File

@ -19,14 +19,8 @@ import javax.ws.rs.core.Response
@Path("bank")
class BankOfCordaWebApi(val rpc: CordaRPCOps) {
data class IssueRequestParams(val amount: Long, val currency: String,
val issueToPartyName: String, val issueToPartyRefAsString: String,
val issuerBankName: String) {
constructor(amount: Long, currency: String,
issueToPartyName: X500Name, issueToPartyRefAsString: String,
issuerBankName: X500Name) : this(amount, currency,
issueToPartyName.toString(), issueToPartyRefAsString,
issuerBankName.toString())
}
val issueToPartyName: X500Name, val issueToPartyRefAsString: String,
val issuerBankName: X500Name)
private companion object {
val logger = loggerFor<BankOfCordaWebApi>()
@ -47,9 +41,9 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
@Consumes(MediaType.APPLICATION_JSON)
fun issueAssetRequest(params: IssueRequestParams): Response {
// 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")
val issuerBankParty = rpc.partyFromName(params.issuerBankName)
val issuerBankParty = rpc.partyFromX500Name(params.issuerBankName)
?: throw Exception("Unable to locate ${params.issuerBankName} in Network Map Service")
val amount = Amount(params.amount, currency(params.currency))

View File

@ -96,7 +96,7 @@ open class RatesFixFlow(protected val tx: TransactionBuilder,
class FixQueryFlow(val fixOf: FixOf, val oracle: Party) : FlowLogic<Fix>() {
@Suspendable
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
val resp = sendAndReceive<ArrayList<Fix>>(oracle, QueryRequest(listOf(fixOf), deadline))

View File

@ -66,7 +66,7 @@ object UpdateBusinessDayFlow {
*/
private fun getRecipients(): Iterable<NodeInfo> {
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
}

View File

@ -94,7 +94,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
require(advertisedServices.containsType(NetworkMapService.type))
val cfg = TestNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = X500Name(DUMMY_MAP.name),
myLegalName = DUMMY_MAP.name,
networkMapService = null)
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))
val cfg = TestNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = X500Name(DUMMY_NOTARY.name),
myLegalName = DUMMY_NOTARY.name,
networkMapService = null)
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot)
}
@ -145,7 +145,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
entropyRoot: BigInteger): MockNetwork.MockNode {
val cfg = TestNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = X500Name(DUMMY_REGULATOR.name),
myLegalName = DUMMY_REGULATOR.name,
networkMapService = null)
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) {
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.

View File

@ -237,7 +237,7 @@ class NetworkMapVisualiser : Application() {
} else if (!viewModel.trackerBoxes.containsKey(tracker)) {
// New flow started up; add.
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)
println("Added: $tracker, $widget")
viewModel.trackerBoxes[tracker] = widget

View File

@ -7,9 +7,7 @@ import javafx.scene.layout.StackPane
import javafx.scene.shape.Circle
import javafx.scene.shape.Line
import javafx.util.Duration
import net.corda.core.crypto.commonName
import net.corda.core.utilities.ProgressTracker
import net.corda.node.services.config.NodeConfiguration
import net.corda.simulation.IRSSimulation
import net.corda.testing.node.MockNetwork
import org.bouncycastle.asn1.x500.X500Name
@ -117,13 +115,13 @@ class VisualiserViewModel {
bankCount = simulation.banks.size
serviceCount = simulation.serviceProviders.size + simulation.regulators.size
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()) {
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()) {
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)
}
}
private val NodeConfiguration.displayName: String get() = try {
X500Name(myLegalName).commonName
} catch(ex: IllegalArgumentException) {
myLegalName
}
}

View File

@ -9,7 +9,7 @@ apply plugin: 'maven-publish'
ext {
deployTo = "./build/nodes"
notaryType = "corda.notary.validating.raft"
notaryName = "Raft"
notaryName = "CN=Raft,O=R3,OU=corda,L=Zurich,C=CH"
advertisedNotary = "$notaryType|$notaryName"
}

View File

@ -14,6 +14,7 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.flows.NotaryFlow
import net.corda.nodeapi.config.SSLConfiguration
import net.corda.notarydemo.flows.DummyIssueAndMove
import org.bouncycastle.asn1.x500.X500Name
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.system.exitProcess
@ -38,7 +39,7 @@ private class NotaryDemoClientApi(val rpc: CordaRPCOps) {
private val counterpartyNode by lazy {
val (parties, partyUpdates) = rpc.networkMapUpdates()
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 {

View File

@ -16,6 +16,7 @@ import net.corda.vega.api.PortfolioApiUtils
import net.corda.vega.api.SwapDataModel
import net.corda.vega.api.SwapDataView
import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name
import org.junit.Test
import java.math.BigDecimal
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 }
private fun getAvailablePartiesFor(partyApi: HttpApi): PortfolioApi.AvailableParties {

View File

@ -20,6 +20,7 @@ import net.corda.vega.flows.SimmRevaluation
import net.corda.vega.portfolio.Portfolio
import net.corda.vega.portfolio.toPortfolio
import net.corda.vega.portfolio.toStateAndRef
import org.bouncycastle.asn1.x500.X500Name
import java.time.LocalDate
import java.time.LocalDateTime
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>)
/**

View File

@ -18,6 +18,7 @@ import net.corda.core.utilities.loggerFor
import net.corda.flows.IssuerFlow.IssuanceRequester
import net.corda.testing.BOC
import net.corda.traderdemo.flow.SellerFlow
import org.bouncycastle.asn1.x500.X500Name
import java.util.*
/**
@ -43,7 +44,7 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
}
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")
val me = rpc.nodeIdentity()
val amounts = calculateRandomlySizedAmounts(amount, 3, 10, Random())
@ -55,8 +56,8 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
Futures.allAsList(resultFutures).getOrThrow()
}
fun runSeller(amount: Amount<Currency> = 1000.0.DOLLARS, counterparty: String) {
val otherParty = rpc.partyFromName(counterparty) ?: throw IllegalStateException("Don't know $counterparty")
fun runSeller(amount: Amount<Currency> = 1000.0.DOLLARS, counterparty: X500Name) {
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 CP sale transaction comes with a prospectus PDF, which will tag along for the ride in an

View File

@ -6,10 +6,8 @@ package net.corda.testing
import com.google.common.net.HostAndPort
import com.google.common.util.concurrent.ListenableFuture
import net.corda.core.contracts.StateRef
import net.corda.core.crypto.Party
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.X509Utilities
import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.*
import net.corda.core.crypto.X509Utilities.getX509Name
import net.corda.core.flows.FlowLogic
import net.corda.core.node.ServiceHub
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.makeTestDataSourceProperties
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x500.X500NameBuilder
import org.bouncycastle.asn1.x500.style.BCStyle
import java.net.ServerSocket
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_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 BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() }
@ -163,7 +162,7 @@ data class TestNodeConfiguration(
override val keyStorePassword: String = "cordacadevpass",
override val trustStorePassword: String = "trustpass",
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 exportJMXto: String = "",
override val devMode: Boolean = true,
@ -183,7 +182,7 @@ fun testConfiguration(baseDirectory: Path, legalName: X500Name, basePort: Int):
emailAddress = "",
keyStorePassword = "cordacadevpass",
trustStorePassword = "trustpass",
dataSourceProperties = makeTestDataSourceProperties(legalName),
dataSourceProperties = makeTestDataSourceProperties(legalName.commonName),
certificateSigningService = URL("http://localhost"),
rpcUsers = emptyList(),
verifierType = VerifierType.InMemory,
@ -200,7 +199,7 @@ fun testConfiguration(baseDirectory: Path, legalName: X500Name, basePort: Int):
}
@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 keyStorePassword: String get() = "cordacadevpass"
override val trustStorePassword: String get() = "trustpass"
@ -209,3 +208,19 @@ fun configureTestSSL(legalName: X500Name = X500Name(MEGA_CORP.name)): SSLConfigu
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()
}

View File

@ -22,7 +22,7 @@ object HttpUtils {
.readTimeout(60, TimeUnit.SECONDS).build()
}
val defaultMapper: ObjectMapper by lazy {
ObjectMapper().registerModule(JavaTimeModule()).registerModule(KotlinModule())
net.corda.jackson.JacksonSupport.createNonRpcMapper()
}
fun putJson(url: URL, data: String): Boolean {

View File

@ -1,6 +1,7 @@
package net.corda.testing.messaging
import com.google.common.net.HostAndPort
import net.corda.core.crypto.X509Utilities
import net.corda.nodeapi.ArtemisMessagingComponent
import net.corda.nodeapi.ArtemisTcpTransport
import net.corda.nodeapi.ConnectionDirection

View File

@ -9,6 +9,7 @@ import net.corda.core.node.NodeInfo
import net.corda.core.node.services.NetworkMapCache
import net.corda.node.services.network.InMemoryNetworkMapCache
import net.corda.testing.MOCK_VERSION_INFO
import net.corda.testing.getTestX509Name
import org.bouncycastle.asn1.x500.X500Name
import rx.Observable
import rx.subjects.PublishSubject
@ -18,8 +19,8 @@ import rx.subjects.PublishSubject
*/
class MockNetworkMapCache : InMemoryNetworkMapCache() {
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_D = Party(X500Name("CN=Bank D,OU=Corda QA Department,O=R3 CEV,L=New York,C=US"), DummyPublicKey("Bank D"))
val BANK_C = Party(getTestX509Name("Bank C"), DummyPublicKey("Bank C"))
val BANK_D = Party(getTestX509Name("Bank D"), DummyPublicKey("Bank D"))
}
override val changed: Observable<NetworkMapCache.MapChange> = PublishSubject.create<NetworkMapCache.MapChange>()

View File

@ -7,6 +7,8 @@ import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import net.corda.core.*
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.flows.FlowLogic
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.testing.MOCK_VERSION_INFO
import net.corda.testing.TestNodeConfiguration
import net.corda.testing.getTestX509Name
import org.apache.activemq.artemis.utils.ReusableLatch
import org.bouncycastle.asn1.x500.X500Name
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.
*/
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
= 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.
*/
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()),
vararg advertisedServices: ServiceInfo): MockNode {
val newNode = forcedID == -1
@ -288,9 +291,9 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
val config = TestNodeConfiguration(
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,
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)
if (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
* doesn't.
*/
fun createTwoNodes(firstNodeName: String? = null,
secondNodeName: String? = null,
fun createTwoNodes(firstNodeName: X500Name? = null,
secondNodeName: X500Name? = null,
nodeFactory: Factory = defaultFactory,
notaryKeyPair: KeyPair? = null): Pair<MockNode, MockNode> {
require(nodes.isEmpty())
@ -372,15 +375,15 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
}
fun createNotaryNode(networkMapAddr: SingleMessageRecipient? = null,
legalName: String? = null,
legalName: X500Name? = 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()),
ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName))
}
fun createPartyNode(networkMapAddr: SingleMessageRecipient,
legalName: String? = null,
legalName: X500Name? = null,
overrideServices: Map<ServiceInfo, KeyPair>? = null): MockNode {
return createNode(networkMapAddr, -1, defaultFactory, true, legalName, overrideServices)
}

View File

@ -74,7 +74,7 @@ open class MockServices(val key: KeyPair = generateKeyPair()) : ServiceHub {
class MockIdentityService(val identities: List<Party>) : IdentityService, SingletonSerializeAsToken() {
private val keyToParties: Map<PublicKey, Party>
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 } }
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(partyRef: PartyAndReference): Party? = partyFromAnonymous(partyRef.party)
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
override fun partyFromName(name: String): Party? = nameToParties[name]
override fun partyFromX500Name(principal: X500Name): Party? = nameToParties[principal.toString()]
override fun partyFromName(name: String): Party? = nameToParties[X500Name(name)]
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.
*/
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()
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
props.setProperty("dataSource.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")

View File

@ -3,6 +3,8 @@ package net.corda.testing.node
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
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.flatMap
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.getFreeLocalPorts
import org.apache.logging.log4j.Level
import org.bouncycastle.asn1.x500.X500Name
import org.junit.After
import org.junit.Rule
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
* 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,
advertisedServices: Set<ServiceInfo> = emptySet(),
rpcUsers: List<User> = emptyList(),
@ -70,7 +73,7 @@ abstract class NodeBasedTest {
}
}
fun startNode(legalName: String,
fun startNode(legalName: X500Name,
platformVersion: Int = 1,
advertisedServices: Set<ServiceInfo> = emptySet(),
rpcUsers: List<User> = emptyList(),
@ -83,18 +86,18 @@ abstract class NodeBasedTest {
mapOf(
"networkMapService" to mapOf(
"address" to networkMapNode.configuration.p2pAddress.toString(),
"legalName" to networkMapNode.info.legalIdentity.name
"legalName" to networkMapNode.info.legalIdentity.name.toString()
)
) + configOverrides
)
return node.networkMapRegistrationFuture.map { node }
}
fun startNotaryCluster(notaryName: String,
fun startNotaryCluster(notaryName: X500Name,
clusterSize: Int,
serviceType: ServiceType = RaftValidatingNotaryService.type): ListenableFuture<List<Node>> {
ServiceIdentityGenerator.generateToDisk(
(0 until clusterSize).map { tempFolder.root.toPath() / "$notaryName-$it" },
(0 until clusterSize).map { tempFolder.root.toPath() / "${notaryName.commonName}-$it" },
serviceType.id,
notaryName)
@ -102,13 +105,13 @@ abstract class NodeBasedTest {
val nodeAddresses = getFreeLocalPorts("localhost", clusterSize).map { it.toString() }
val masterNodeFuture = startNode(
"$notaryName-0",
X509Utilities.getDevX509Name("${notaryName.commonName}-0"),
advertisedServices = setOf(serviceInfo),
configOverrides = mapOf("notaryNodeAddress" to nodeAddresses[0]))
val remainingNodesFutures = (1 until clusterSize).map {
startNode(
"$notaryName-$it",
X509Utilities.getDevX509Name("${notaryName.commonName}-$it"),
advertisedServices = setOf(serviceInfo),
configOverrides = mapOf(
"notaryNodeAddress" to nodeAddresses[it],
@ -120,18 +123,18 @@ abstract class NodeBasedTest {
}
}
private fun startNodeInternal(legalName: String,
private fun startNodeInternal(legalName: X500Name,
platformVersion: Int,
advertisedServices: Set<ServiceInfo>,
rpcUsers: List<User>,
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 config = ConfigHelper.loadConfig(
baseDirectory = baseDirectory,
allowMissingConfig = true,
configOverrides = mapOf(
"myLegalName" to legalName,
"myLegalName" to legalName.toString(),
"p2pAddress" to localPort[0].toString(),
"rpcAddress" to localPort[1].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))
node.start()
nodes += node
thread(name = legalName) {
thread(name = legalName.commonName) {
node.run()
}
return node

View File

@ -1,6 +1,7 @@
package net.corda.demobench.model
import com.typesafe.config.*
import net.corda.core.crypto.location
import net.corda.nodeapi.User
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x500.style.BCStyle
@ -26,7 +27,7 @@ class NodeConfig(
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)
override val pluginDir: Path = nodeDir.resolve("plugins")
val explorerDir: Path = baseDir.resolve("$key-explorer")

View File

@ -144,7 +144,7 @@ class NodeConfigTest {
assertEquals(prettyPrint("{"
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
+ "\"h2port\":30001,"
+ "\"myLegalName\":\"My Name\","
+ "\"myLegalName\":\"CN=My Name,OU=Corda QA Department,O=R3 CEV,L=New York,C=US\","
+ "\"p2pAddress\":\"localhost:10001\","
+ "\"rpcAddress\":\"localhost:40002\","
+ "\"rpcUsers\":["
@ -166,12 +166,12 @@ class NodeConfigTest {
services = listOf("my.service"),
users = listOf(user("jenny"))
)
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
assertEquals(prettyPrint("{"
+ "\"extraAdvertisedServiceIds\":[\"my.service\"],"
+ "\"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\"},"
+ "\"p2pAddress\":\"localhost:10001\","
+ "\"rpcAddress\":\"localhost:40002\","
@ -194,7 +194,7 @@ class NodeConfigTest {
services = listOf("my.service"),
users = listOf(user("jenny"))
)
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
val nodeConfig = config.toFileConfig()
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))
@ -203,7 +203,6 @@ class NodeConfigTest {
val fullConfig = nodeConfig.parseAs<FullNodeConfiguration>()
assertEquals(myLegalName, fullConfig.myLegalName)
assertEquals("London", fullConfig.nearestCity)
assertEquals(localPort(40002), fullConfig.rpcAddress)
assertEquals(localPort(10001), fullConfig.p2pAddress)
assertEquals(listOf("my.service"), fullConfig.extraAdvertisedServiceIds)
@ -224,7 +223,7 @@ class NodeConfigTest {
services = listOf("my.service"),
users = listOf(user("jenny"))
)
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 12345)
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 12345)
val nodeConfig = config.toFileConfig()
.withValue("basedir", ConfigValueFactory.fromAnyRef(baseDir.toString()))

View File

@ -101,7 +101,7 @@ class NodeControllerTest {
@Test
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"))
config.networkMap = NetworkMapConfig(X500Name(DUMMY_NOTARY.name), 10000)
config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 10000)
assertFalse(config.isNetworkMap())
assertFalse(controller.hasNetworkMap())

View File

@ -266,7 +266,7 @@ fun main(args: Array<String>) {
// Party pay requests.
eventGenerator.moveCashGenerator.combine(Generator.pickOne(parties)) { command, (party, rpc) ->
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())
}

View File

@ -5,11 +5,11 @@ import net.corda.core.crypto.commonName
import org.bouncycastle.asn1.x500.X500Name
object PartyNameFormatter {
val short = object : Formatter<String> {
override fun format(value: String) = X500Name(value).commonName
val short = object : Formatter<X500Name> {
override fun format(value: X500Name) = value.commonName
}
val full = object : Formatter<String> {
override fun format(value: String): String = value
val full = object : Formatter<X500Name> {
override fun format(value: X500Name): String = value.toString()
}
}

View File

@ -22,11 +22,7 @@ import net.corda.client.jfx.utils.map
import net.corda.client.jfx.utils.sequence
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.*
import net.corda.core.crypto.AbstractParty
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.crypto.*
import net.corda.core.node.NodeInfo
import net.corda.explorer.AmountDiff
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.sign
import net.corda.explorer.ui.setCustomCellFactory
import org.bouncycastle.asn1.x500.X500Name
import tornadofx.*
import java.util.*
@ -110,8 +107,8 @@ class TransactionViewer : CordaView("Transactions") {
"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) } },
"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 } } },
"Output Party" to { tx, s -> tx.outputParties.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?.commonName?.contains(s, true) ?: false } } },
"Command Type" to { tx, s -> tx.commandTypes.any { it.simpleName.contains(s, true) } }
)
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 {
it.value?.legalIdentity?.let { formatter.format(it.name) }
}.filterNotNull().toSet().joinToString(separator)
@ -294,4 +291,4 @@ private fun calculateTotalEquiv(identity: NodeInfo?,
.sum() else 0
return AmountDiff.fromLong(outputs.sum() - inputs.sum() - issuedAmount, reportingCurrency)
}
}

View File

@ -24,6 +24,7 @@ import net.corda.core.contracts.Amount
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.withoutIssuer
import net.corda.core.crypto.AbstractParty
import net.corda.core.crypto.commonName
import net.corda.explorer.formatters.AmountFormatter
import net.corda.explorer.formatters.PartyNameFormatter
import net.corda.explorer.identicon.identicon
@ -147,7 +148,7 @@ class CashViewer : CordaView("Cash") {
*/
val searchField = SearchField(cashStates,
"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) {
button("New Transaction", FontAwesomeIconView(FontAwesomeIcon.PLUS)) {

View File

@ -22,6 +22,7 @@ import net.corda.core.contracts.sumOrNull
import net.corda.core.contracts.withoutIssuer
import net.corda.core.crypto.AbstractParty
import net.corda.core.crypto.Party
import net.corda.core.crypto.commonName
import net.corda.core.flows.FlowException
import net.corda.core.getOrThrow
import net.corda.core.messaging.startFlow

View File

@ -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> {
if (from.isEmpty()) {

View File

@ -7,6 +7,8 @@ import com.google.common.util.concurrent.ListeningScheduledExecutorService
import com.google.common.util.concurrent.SettableFuture
import com.typesafe.config.Config
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.map
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.server.impl.ActiveMQServerImpl
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager
import org.bouncycastle.asn1.x500.X500Name
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.ConcurrentHashMap
@ -43,7 +46,7 @@ import java.util.concurrent.atomic.AtomicInteger
*/
interface VerifierExposedDSLInterface : DriverDSLExposedInterface {
/** 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] */
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()
return driverDSL.executorService.submit<VerificationRequestorHandle> {
startVerificationRequestorInternal(name, hostAndPort)
}
}
private fun startVerificationRequestorInternal(name: String, hostAndPort: HostAndPort): VerificationRequestorHandle {
val baseDir = driverDSL.driverDirectory / name
private fun startVerificationRequestorInternal(name: X500Name, hostAndPort: HostAndPort): VerificationRequestorHandle {
val baseDir = driverDSL.driverDirectory / name.commonName
val sslConfig = object : SSLConfiguration {
override val certificatesDirectory = baseDir / "certificates"
override val keyStorePassword: String get() = "cordacadevpass"
@ -246,8 +249,8 @@ data class VerifierDriverDSL(
val id = verifierCount.andIncrement
val jdwpPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null
val processFuture = driverDSL.executorService.submit<Process> {
val verifierName = "verifier$id"
val baseDirectory = driverDSL.driverDirectory / verifierName
val verifierName = X509Utilities.getDevX509Name("verifier$id")
val baseDirectory = driverDSL.driverDirectory / verifierName.commonName
val config = createConfiguration(baseDirectory, address)
val configFilename = "verifier.conf"
writeConfig(baseDirectory, configFilename, config)