mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Change party to hold an X.500 name
Change the legal name of parties to be an X500 name. This ensures that we aren't converting between common names and X500 names in various places, eliminating substantial scope for error in the conversion process. As a result, all node names must now be full X500 names, which has impact on most configurations.
This commit is contained in:
parent
b64e7f51f6
commit
25dbac0f07
@ -17,6 +17,8 @@ import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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?
|
||||
|
||||
/**
|
||||
|
@ -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?
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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`() {
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
@ -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}\")" )
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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) }
|
||||
|
@ -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>)
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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`() {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
})
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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\"")
|
||||
|
@ -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);
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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())))
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)) }
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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`() {
|
||||
|
@ -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())
|
||||
|
@ -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)) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 ...")
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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>)
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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>()
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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()))
|
||||
|
@ -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())
|
||||
|
@ -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())
|
||||
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user