From de3468f8a724fb69192780f7e3b2f67b88efe5c7 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Tue, 12 Sep 2017 01:03:10 +0100 Subject: [PATCH] Replace X500Name with CordaX500Name (#1447) Replace X500Name with CordaX500Name, which enforces the specific constraints Corda expects on legal/service identity names. --- .../corda/client/jackson/JacksonSupport.kt | 28 +-- .../corda/client/jfx/NodeMonitorModelTest.kt | 6 +- .../rpc/StandaloneCordaRPCJavaClientTest.java | 3 +- .../kotlin/rpc/StandaloneCordaRPClientTest.kt | 8 +- .../net/corda/core/identity/AbstractParty.kt | 3 +- .../net/corda/core/identity/AnonymousParty.kt | 3 +- .../net/corda/core/identity/CordaX500Name.kt | 126 +++++++++++++ .../kotlin/net/corda/core/identity/Party.kt | 9 +- .../core/identity/PartyAndCertificate.kt | 3 +- .../corda/core/internal/LegalNameValidator.kt | 117 ++++++++++++ .../net/corda/core/messaging/CordaRPCOps.kt | 6 +- .../net/corda/core/messaging/Messaging.kt | 1 - .../kotlin/net/corda/core/node/NodeInfo.kt | 1 - .../core/node/services/IdentityService.kt | 8 +- .../core/node/services/NetworkMapCache.kt | 6 +- .../corda/core/node/services/ServiceInfo.kt | 6 +- .../core/utilities/LegalNameValidator.kt | 170 ------------------ .../net/corda/core/utilities/X500NameUtils.kt | 12 +- .../corda/core/crypto/CompositeKeyTests.kt | 4 +- .../corda/core/identity/CordaX500NameTest.kt | 63 +++++++ .../core/identity/PartyAndCertificateTest.kt | 3 +- .../core/internal/LegalNameValidatorTest.kt | 102 +++++++++++ .../net/corda/core/node/ServiceInfoTests.kt | 4 +- .../core/utilities/LegalNameValidatorTest.kt | 132 -------------- .../java/net/corda/docs/FlowCookbookJava.java | 6 +- .../kotlin/net/corda/docs/FlowCookbook.kt | 5 +- .../net/corda/finance/contracts/asset/Cash.kt | 4 +- .../finance/contracts/asset/Obligation.kt | 4 +- .../net/corda/nodeapi/ArtemisTcpTransport.kt | 3 +- .../corda/nodeapi/config/ConfigUtilities.kt | 6 +- .../corda/nodeapi/config/ConfigParsingTest.kt | 9 +- .../node/services/AdvertisedServiceTests.kt | 4 +- .../node/services/BFTNotaryServiceTests.kt | 4 +- .../node/services/RaftNotaryServiceTests.kt | 4 +- .../messaging/MQSecurityAsNodeTest.kt | 2 +- .../services/messaging/P2PMessagingTest.kt | 11 +- .../services/messaging/P2PSecurityTest.kt | 8 +- .../net/corda/node/internal/AbstractNode.kt | 19 +- .../corda/node/internal/CordaRPCOpsImpl.kt | 6 +- .../kotlin/net/corda/node/internal/Node.kt | 4 +- .../node/services/config/ConfigUtilities.kt | 18 +- .../node/services/config/NodeConfiguration.kt | 8 +- .../identity/InMemoryIdentityService.kt | 12 +- .../identity/PersistentIdentityService.kt | 22 +-- .../net/corda/node/services/keys/KMSUtils.kt | 2 +- .../messaging/ArtemisMessagingServer.kt | 17 +- .../node/services/messaging/Messaging.kt | 4 +- .../services/messaging/NodeMessagingClient.kt | 15 +- .../node/services/messaging/RPCServer.kt | 12 +- .../network/PersistentNetworkMapCache.kt | 9 +- ...bstractPartyToX500NameAsStringConverter.kt | 8 +- .../BFTNonValidatingNotaryService.kt | 7 +- .../PersistentUniquenessProvider.kt | 11 +- .../corda/node/utilities/KeyStoreUtilities.kt | 10 +- .../utilities/ServiceIdentityGenerator.kt | 4 +- .../net/corda/node/utilities/X509Utilities.kt | 25 ++- .../registration/NetworkRegistrationHelper.kt | 6 +- .../kotlin/net/corda/node/CordappSmokeTest.kt | 4 +- .../node/messaging/TwoPartyTradeFlowTests.kt | 4 +- .../corda/node/services/NotaryChangeTests.kt | 5 +- .../events/NodeSchedulerServiceTest.kt | 7 +- .../network/AbstractNetworkMapServiceTest.kt | 9 +- .../network/InMemoryIdentityServiceTests.kt | 18 +- .../network/PersistentIdentityServiceTests.kt | 18 +- .../network/PersistentNetworkMapCacheTest.kt | 10 +- .../statemachine/FlowFrameworkTests.kt | 8 +- .../node/services/vault/VaultQueryTests.kt | 9 +- .../corda/node/utilities/X509UtilitiesTest.kt | 9 +- .../NetworkisRegistrationHelperTest.kt | 2 + samples/attachment-demo/build.gradle | 4 +- samples/bank-of-corda-demo/build.gradle | 4 +- .../net/corda/bank/BankOfCordaDriver.kt | 4 +- .../net/corda/bank/api/BankOfCordaWebApi.kt | 8 +- samples/irs-demo/build.gradle | 4 +- .../corda/irs/api/NodeInterestRatesTest.kt | 4 +- .../net/corda/netmap/VisualiserViewModel.kt | 6 +- .../net/corda/netmap/simulation/Simulation.kt | 7 +- .../net/corda/notarydemo/BFTNotaryCordform.kt | 8 +- .../corda/notarydemo/RaftNotaryCordform.kt | 10 +- .../corda/notarydemo/SingleNotaryCordform.kt | 2 +- samples/simm-valuation-demo/build.gradle | 4 +- .../net/corda/vega/SimmValuationTest.kt | 8 +- .../kotlin/net/corda/vega/api/PortfolioApi.kt | 3 +- samples/trader-demo/build.gradle | 4 +- .../corda/traderdemo/TraderDemoClientApi.kt | 6 +- .../kotlin/net/corda/demorun/DemoRunner.kt | 3 +- .../net/corda/demorun/util/DemoUtils.kt | 3 +- .../kotlin/net/corda/testing/NodeTestUtils.kt | 6 +- .../kotlin/net/corda/testing/RPCDriver.kt | 16 +- .../kotlin/net/corda/testing/driver/Driver.kt | 38 ++-- .../testing/driver/NetworkMapStartStrategy.kt | 6 +- .../testing/node/InMemoryMessagingNetwork.kt | 13 +- .../corda/testing/node/MockNetworkMapCache.kt | 6 +- .../kotlin/net/corda/testing/node/MockNode.kt | 14 +- .../net/corda/testing/node/NodeBasedTest.kt | 21 ++- .../net/corda/smoketesting/NodeConfig.kt | 5 +- .../kotlin/net/corda/testing/CoreTestUtils.kt | 18 +- .../kotlin/net/corda/testing/TestConstants.kt | 21 +-- .../corda/testing/messaging/SimpleMQClient.kt | 5 +- .../corda/demobench/model/InstallFactory.kt | 6 +- .../corda/demobench/model/NetworkMapConfig.kt | 8 +- .../net/corda/demobench/model/NodeConfig.kt | 3 +- .../corda/demobench/model/NodeController.kt | 10 +- .../kotlin/net/corda/demobench/pty/R3Pty.kt | 5 +- .../net/corda/demobench/views/NodeTabView.kt | 12 +- .../corda/demobench/views/NodeTerminalView.kt | 1 - .../demobench/model/NetworkMapConfigTest.kt | 6 +- .../corda/demobench/model/NodeConfigTest.kt | 13 +- .../demobench/model/NodeControllerTest.kt | 56 +++--- .../net/corda/explorer/ExplorerSimulation.kt | 6 +- .../explorer/formatters/PartyNameFormatter.kt | 9 +- .../corda/explorer/views/TransactionViewer.kt | 5 +- .../net/corda/verifier/GeneratedLedger.kt | 7 +- .../net/corda/verifier/VerifierDriver.kt | 12 +- 114 files changed, 867 insertions(+), 769 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/identity/CordaX500Name.kt create mode 100644 core/src/main/kotlin/net/corda/core/internal/LegalNameValidator.kt delete mode 100644 core/src/main/kotlin/net/corda/core/utilities/LegalNameValidator.kt create mode 100644 core/src/test/kotlin/net/corda/core/identity/CordaX500NameTest.kt create mode 100644 core/src/test/kotlin/net/corda/core/internal/LegalNameValidatorTest.kt delete mode 100644 core/src/test/kotlin/net/corda/core/utilities/LegalNameValidatorTest.kt diff --git a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt index a8418809da..de028ed2e6 100644 --- a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt +++ b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt @@ -15,6 +15,7 @@ import net.corda.core.crypto.* import net.corda.core.crypto.CompositeKey import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo @@ -30,7 +31,6 @@ import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.parsePublicKeyBase58 import net.corda.core.utilities.toBase58String import net.i2p.crypto.eddsa.EdDSAPublicKey -import org.bouncycastle.asn1.x500.X500Name import java.math.BigDecimal import java.security.PublicKey import java.util.* @@ -46,25 +46,25 @@ object JacksonSupport { // If you change this API please update the docs in the docsite (json.rst) interface PartyObjectMapper { - fun partyFromX500Name(name: X500Name): Party? + fun partyFromX500Name(name: CordaX500Name): Party? fun partyFromKey(owningKey: PublicKey): Party? fun partiesFromName(query: String): Set } class RpcObjectMapper(val rpc: CordaRPCOps, factory: JsonFactory, val fuzzyIdentityMatch: Boolean) : PartyObjectMapper, ObjectMapper(factory) { - override fun partyFromX500Name(name: X500Name): Party? = rpc.partyFromX500Name(name) + override fun partyFromX500Name(name: CordaX500Name): Party? = rpc.partyFromX500Name(name) override fun partyFromKey(owningKey: PublicKey): Party? = rpc.partyFromKey(owningKey) override fun partiesFromName(query: String) = rpc.partiesFromName(query, fuzzyIdentityMatch) } class IdentityObjectMapper(val identityService: IdentityService, factory: JsonFactory, val fuzzyIdentityMatch: Boolean) : PartyObjectMapper, ObjectMapper(factory) { - override fun partyFromX500Name(name: X500Name): Party? = identityService.partyFromX500Name(name) + override fun partyFromX500Name(name: CordaX500Name): Party? = identityService.partyFromX500Name(name) override fun partyFromKey(owningKey: PublicKey): Party? = identityService.partyFromKey(owningKey) override fun partiesFromName(query: String) = identityService.partiesFromName(query, fuzzyIdentityMatch) } class NoPartyObjectMapper(factory: JsonFactory) : PartyObjectMapper, ObjectMapper(factory) { - override fun partyFromX500Name(name: X500Name): Party? = throw UnsupportedOperationException() + override fun partyFromX500Name(name: CordaX500Name): Party? = throw UnsupportedOperationException() override fun partyFromKey(owningKey: PublicKey): Party? = throw UnsupportedOperationException() override fun partiesFromName(query: String) = throw UnsupportedOperationException() } @@ -105,8 +105,8 @@ object JacksonSupport { addSerializer(OpaqueBytes::class.java, OpaqueBytesSerializer) // For X.500 distinguished names - addDeserializer(X500Name::class.java, X500NameDeserializer) - addSerializer(X500Name::class.java, X500NameSerializer) + addDeserializer(CordaX500Name::class.java, CordaX500NameDeserializer) + addSerializer(CordaX500Name::class.java, CordaX500NameSerializer) // Mixins for transaction types to prevent some properties from being serialized setMixInAnnotation(SignedTransaction::class.java, SignedTransactionMixin::class.java) @@ -191,7 +191,7 @@ object JacksonSupport { // Base58 keys never include an equals character, while X.500 names always will, so we use that to determine // how to parse the content return if (parser.text.contains("=")) { - val principal = X500Name(parser.text) + val principal = CordaX500Name.parse(parser.text) mapper.partyFromX500Name(principal) ?: throw JsonParseException(parser, "Could not find a Party with name $principal") } else { val nameMatches = mapper.partiesFromName(parser.text) @@ -211,22 +211,22 @@ object JacksonSupport { } } - object X500NameSerializer : JsonSerializer() { - override fun serialize(obj: X500Name, generator: JsonGenerator, provider: SerializerProvider) { + object CordaX500NameSerializer : JsonSerializer() { + override fun serialize(obj: CordaX500Name, generator: JsonGenerator, provider: SerializerProvider) { generator.writeString(obj.toString()) } } - object X500NameDeserializer : JsonDeserializer() { - override fun deserialize(parser: JsonParser, context: DeserializationContext): X500Name { + object CordaX500NameDeserializer : JsonDeserializer() { + override fun deserialize(parser: JsonParser, context: DeserializationContext): CordaX500Name { if (parser.currentToken == JsonToken.FIELD_NAME) { parser.nextToken() } return try { - X500Name(parser.text) + CordaX500Name.parse(parser.text) } catch(ex: IllegalArgumentException) { - throw JsonParseException(parser, "Invalid X.500 name ${parser.text}: ${ex.message}", ex) + throw JsonParseException(parser, "Invalid Corda X.500 name ${parser.text}: ${ex.message}", ex) } } } diff --git a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt index 44dfcf34a6..ccd40059d4 100644 --- a/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt +++ b/client/jfx/src/integration-test/kotlin/net/corda/client/jfx/NodeMonitorModelTest.kt @@ -8,6 +8,7 @@ import net.corda.core.crypto.isFulfilledBy import net.corda.core.crypto.keys import net.corda.core.flows.FlowInitiator import net.corda.core.flows.StateMachineRunId +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.bufferUntilSubscribed import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.StateMachineTransactionMapping @@ -25,14 +26,13 @@ import net.corda.finance.USD import net.corda.finance.flows.CashExitFlow import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow -import net.corda.node.services.network.NetworkMapService import net.corda.node.services.FlowPermissions.Companion.startFlowPermission +import net.corda.node.services.network.NetworkMapService import net.corda.node.services.transactions.SimpleNotaryService import net.corda.nodeapi.User import net.corda.testing.* import net.corda.testing.driver.driver import net.corda.testing.node.DriverBasedTest -import org.bouncycastle.asn1.x500.X500Name import org.junit.Test import rx.Observable @@ -50,7 +50,7 @@ class NodeMonitorModelTest : DriverBasedTest() { lateinit var transactions: Observable lateinit var vaultUpdates: Observable> lateinit var networkMapUpdates: Observable - lateinit var newNode: (X500Name) -> NodeInfo + lateinit var newNode: (CordaX500Name) -> NodeInfo override fun setup() = driver { val cashUser = User("user1", "test", permissions = setOf( diff --git a/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java b/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java index 5a8a8349eb..41dc849629 100644 --- a/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java +++ b/client/rpc/src/smoke-test/java/net/corda/java/rpc/StandaloneCordaRPCJavaClientTest.java @@ -2,6 +2,7 @@ package net.corda.java.rpc; import net.corda.client.rpc.CordaRPCConnection; import net.corda.core.contracts.Amount; +import net.corda.core.identity.CordaX500Name; import net.corda.core.messaging.CordaRPCOps; import net.corda.core.messaging.FlowHandle; import net.corda.core.node.NodeInfo; @@ -43,7 +44,7 @@ public class StandaloneCordaRPCJavaClientTest { private NodeInfo notaryNode; private NodeConfig notaryConfig = new NodeConfig( - X500NameUtils.getX500Name("Notary Service", "Zurich", "CH"), + new CordaX500Name("Notary Service", "Zurich", "CH"), port.getAndIncrement(), port.getAndIncrement(), port.getAndIncrement(), diff --git a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt index 4fab64c88f..56fe7d7b8c 100644 --- a/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt +++ b/client/rpc/src/smoke-test/kotlin/net/corda/kotlin/rpc/StandaloneCordaRPClientTest.kt @@ -4,12 +4,16 @@ import com.google.common.hash.Hashing import com.google.common.hash.HashingInputStream import net.corda.client.rpc.CordaRPCConnection import net.corda.core.crypto.SecureHash +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.* import net.corda.core.messaging.* import net.corda.core.node.NodeInfo import net.corda.core.node.services.Vault import net.corda.core.node.services.vault.* -import net.corda.core.utilities.* +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.getOrThrow +import net.corda.core.utilities.loggerFor +import net.corda.core.utilities.seconds import net.corda.finance.DOLLARS import net.corda.finance.POUNDS import net.corda.finance.SWISS_FRANCS @@ -54,7 +58,7 @@ class StandaloneCordaRPClientTest { private lateinit var notaryNode: NodeInfo private val notaryConfig = NodeConfig( - legalName = getX500Name(O = "Notary Service", OU = "corda", L = "Zurich", C = "CH"), + legalName = CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), p2pPort = port.andIncrement, rpcPort = port.andIncrement, webPort = port.andIncrement, diff --git a/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt b/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt index b549f33e11..6f6f1a8109 100644 --- a/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt +++ b/core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt @@ -3,7 +3,6 @@ package net.corda.core.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.OpaqueBytes -import org.bouncycastle.asn1.x500.X500Name import java.security.PublicKey /** @@ -15,7 +14,7 @@ abstract class AbstractParty(val owningKey: PublicKey) { /** Anonymised parties do not include any detail apart from owning key, so equality is dependent solely on the key */ override fun equals(other: Any?): Boolean = other === this || other is AbstractParty && other.owningKey == owningKey override fun hashCode(): Int = owningKey.hashCode() - abstract fun nameOrNull(): X500Name? + abstract fun nameOrNull(): CordaX500Name? /** * Build a reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal diff --git a/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt b/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt index ed6e5b3707..086d06c6c9 100644 --- a/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt +++ b/core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt @@ -3,7 +3,6 @@ package net.corda.core.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.crypto.toStringShort import net.corda.core.utilities.OpaqueBytes -import org.bouncycastle.asn1.x500.X500Name import java.security.PublicKey /** @@ -11,7 +10,7 @@ import java.security.PublicKey * information such as name. It is intended to represent a party on the distributed ledger. */ class AnonymousParty(owningKey: PublicKey) : AbstractParty(owningKey) { - override fun nameOrNull(): X500Name? = null + override fun nameOrNull(): CordaX500Name? = null override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes) override fun toString() = "Anonymous(${owningKey.toStringShort()})" } \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/identity/CordaX500Name.kt b/core/src/main/kotlin/net/corda/core/identity/CordaX500Name.kt new file mode 100644 index 0000000000..486ff93429 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/identity/CordaX500Name.kt @@ -0,0 +1,126 @@ +package net.corda.core.identity + +import net.corda.core.internal.LegalNameValidator +import net.corda.core.serialization.CordaSerializable +import net.corda.core.utilities.countryCodes +import org.bouncycastle.asn1.ASN1Encodable +import org.bouncycastle.asn1.ASN1ObjectIdentifier +import org.bouncycastle.asn1.x500.AttributeTypeAndValue +import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.asn1.x500.X500NameBuilder +import org.bouncycastle.asn1.x500.style.BCStyle + +/** + * X.500 distinguished name data type customised to how Corda uses names. This restricts the attributes to those Corda + * supports, and requires that organsation, locality and country attributes are specified. See also RFC 4519 for + * the underlying attribute type definitions + * + * @property commonName optional name by the which the entity is usually known. Used only for services (for + * organisations, the [organisation] property is the name). Corresponds to the "CN" attribute type. + * @property organisationUnit optional name of a unit within the [organisation]. Corresponds to the "OU" attribute type. + * @property organisation name of the organisation. Corresponds to the "O" attribute type. + * @property locality locality of the organisation, typically nearest major city. For distributed services this would be + * where one of the organisations is based. Corresponds to the "L" attribute type. + * @property state the full name of the state or province the organisation is based in. Corresponds to the "ST" + * attribute type. + * @property country country the organisation is in, as an ISO 3166-1 2-letter country code. Corresponds to the "C" + * attribute type. + */ +@CordaSerializable +data class CordaX500Name(val commonName: String?, + val organisationUnit: String?, + val organisation: String, + val locality: String, + val state: String?, + val country: String) { + init { + // Legal name checks. + LegalNameValidator.validateLegalName(organisation) + + // Attribute data width checks. + require(country.length == LENGTH_COUNTRY) { "Invalid country '$country' Country code must be 2 letters ISO code " } + require(country.toUpperCase() == country) { "Country code should be in upper case." } + require(countryCodes.contains(country)) { "Invalid country code '${country}'" } + + require(organisation.length < MAX_LENGTH_ORGANISATION) { "Organisation attribute (O) must contain less then $MAX_LENGTH_ORGANISATION characters." } + require(locality.length < MAX_LENGTH_LOCALITY) { "Locality attribute (L) must contain less then $MAX_LENGTH_LOCALITY characters." } + + state?.let { require(it.length < MAX_LENGTH_STATE) { "State attribute (ST) must contain less then $MAX_LENGTH_STATE characters." } } + organisationUnit?.let { require(it.length < MAX_LENGTH_ORGANISATION_UNIT) { "Organisation Unit attribute (OU) must contain less then $MAX_LENGTH_ORGANISATION_UNIT characters." } } + commonName?.let { require(it.length < MAX_LENGTH_COMMON_NAME) { "Common Name attribute (CN) must contain less then $MAX_LENGTH_COMMON_NAME characters." } } + } + constructor(commonName: String, organisation: String, locality: String, country: String) : this(null, commonName, organisation, locality, null, country) + /** + * @param organisation name of the organisation. + * @param locality locality of the organisation, typically nearest major city. + * @param country country the organisation is in, as an ISO 3166-1 2-letter country code. + */ + constructor(organisation: String, locality: String, country: String) : this(null, null, organisation, locality, null, country) + + companion object { + const val LENGTH_COUNTRY = 2 + const val MAX_LENGTH_ORGANISATION = 128 + const val MAX_LENGTH_LOCALITY = 64 + const val MAX_LENGTH_STATE = 64 + const val MAX_LENGTH_ORGANISATION_UNIT = 64 + const val MAX_LENGTH_COMMON_NAME = 64 + private val mandatoryAttributes = setOf(BCStyle.O, BCStyle.C, BCStyle.L) + private val supportedAttributes = mandatoryAttributes + setOf(BCStyle.CN, BCStyle.ST, BCStyle.OU) + + @JvmStatic + fun build(x500Name: X500Name) : CordaX500Name { + val rDNs = x500Name.rdNs.flatMap { it.typesAndValues.toList() } + val attrsMap: Map = rDNs.associateBy(AttributeTypeAndValue::getType, AttributeTypeAndValue::getValue) + val attributes = attrsMap.keys + + // Duplicate attribute value checks. + require(attributes.size == attributes.toSet().size) { "X500Name contain duplicate attribute." } + + // Mandatory attribute checks. + require(attributes.containsAll(mandatoryAttributes)) { + val missingAttributes = mandatoryAttributes.subtract(attributes).map { BCStyle.INSTANCE.oidToDisplayName(it) } + "The following attribute${if (missingAttributes.size > 1) "s are" else " is"} missing from the legal name : $missingAttributes" + } + + // Supported attribute checks. + require(attributes.subtract(supportedAttributes).isEmpty()) { + val unsupportedAttributes = attributes.subtract(supportedAttributes).map { BCStyle.INSTANCE.oidToDisplayName(it) } + "The following attribute${if (unsupportedAttributes.size > 1) "s are" else " is"} not supported in Corda :$unsupportedAttributes" + } + + val CN = attrsMap[BCStyle.CN]?.toString() + val OU = attrsMap[BCStyle.OU]?.toString() + val O = attrsMap[BCStyle.O]?.toString() ?: throw IllegalArgumentException("Corda X.500 names must include an O attribute") + val L = attrsMap[BCStyle.L]?.toString() ?: throw IllegalArgumentException("Corda X.500 names must include an L attribute") + val ST = attrsMap[BCStyle.ST]?.toString() + val C = attrsMap[BCStyle.C]?.toString() ?: throw IllegalArgumentException("Corda X.500 names must include an C attribute") + return CordaX500Name(CN, OU, O, L, ST, C) + } + @JvmStatic + fun parse(name: String) : CordaX500Name = build(X500Name(name)) + } + + @Transient + private var x500Cache: X500Name? = null + + override fun toString(): String = x500Name.toString() + + /** + * Return the underlying X.500 name from this Corda-safe X.500 name. These are guaranteed to have a consistent + * ordering, such that their `toString()` function returns the same value every time for the same [CordaX500Name]. + */ + val x500Name: X500Name + get() { + if (x500Cache == null) { + x500Cache = X500NameBuilder(BCStyle.INSTANCE).apply { + addRDN(BCStyle.C, country) + state?.let { addRDN(BCStyle.ST, it) } + addRDN(BCStyle.L, locality) + addRDN(BCStyle.O, organisation) + organisationUnit?.let { addRDN(BCStyle.OU, it) } + commonName?.let { addRDN(BCStyle.CN, it) } + }.build() + } + return x500Cache!! + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/identity/Party.kt b/core/src/main/kotlin/net/corda/core/identity/Party.kt index f25d6446d1..16307fbe2e 100644 --- a/core/src/main/kotlin/net/corda/core/identity/Party.kt +++ b/core/src/main/kotlin/net/corda/core/identity/Party.kt @@ -1,10 +1,9 @@ package net.corda.core.identity import net.corda.core.contracts.PartyAndReference -import net.corda.core.crypto.Crypto import net.corda.core.crypto.CompositeKey +import net.corda.core.crypto.Crypto import net.corda.core.utilities.OpaqueBytes -import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey @@ -27,9 +26,9 @@ import java.security.PublicKey * * @see CompositeKey */ -class Party(val name: X500Name, owningKey: PublicKey) : AbstractParty(owningKey) { - constructor(certificate: X509CertificateHolder) : this(certificate.subject, Crypto.toSupportedPublicKey(certificate.subjectPublicKeyInfo)) - override fun nameOrNull(): X500Name = name +class Party(val name: CordaX500Name, owningKey: PublicKey) : AbstractParty(owningKey) { + constructor(certificate: X509CertificateHolder) : this(CordaX500Name.build(certificate.subject), Crypto.toSupportedPublicKey(certificate.subjectPublicKeyInfo)) + override fun nameOrNull(): CordaX500Name = name fun anonymise(): AnonymousParty = AnonymousParty(owningKey) override fun ref(bytes: OpaqueBytes): PartyAndReference = PartyAndReference(this, bytes) override fun toString() = name.toString() diff --git a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt index e6f972798a..df82843500 100644 --- a/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt +++ b/core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt @@ -1,7 +1,6 @@ package net.corda.core.identity import net.corda.core.internal.toX509CertHolder -import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.PublicKey import java.security.cert.* @@ -24,7 +23,7 @@ class PartyAndCertificate(val certPath: CertPath) { @Transient val party: Party = Party(certificate) val owningKey: PublicKey get() = party.owningKey - val name: X500Name get() = party.name + val name: CordaX500Name get() = party.name operator fun component1(): Party = party operator fun component2(): X509CertificateHolder = certificate diff --git a/core/src/main/kotlin/net/corda/core/internal/LegalNameValidator.kt b/core/src/main/kotlin/net/corda/core/internal/LegalNameValidator.kt new file mode 100644 index 0000000000..967afc5e7a --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/LegalNameValidator.kt @@ -0,0 +1,117 @@ +package net.corda.core.internal + +import java.lang.Character.UnicodeScript.* +import java.text.Normalizer +import java.util.regex.Pattern +import javax.security.auth.x500.X500Principal + +object LegalNameValidator { + /** + * The validation function will validate the input string using the following rules: + * + * - No blacklisted words like "node", "server". + * - Restrict names to Latin scripts for now to avoid right-to-left issues, debugging issues when we can't pronounce + * names over the phone, and character confusability attacks. + * - Must consist of at least three letters and should start with a capital letter. + * - No commas or equals signs. + * - No dollars or quote marks, we might need to relax the quote mark constraint in future to handle Irish company names. + * + * @throws IllegalArgumentException if the name does not meet the required rules. The message indicates why not. + */ + fun validateLegalName(normalizedLegalName: String) { + Rule.legalNameRules.forEach { it.validate(normalizedLegalName) } + } + + /** + * The normalize function will trim the input string, replace any multiple spaces with a single space, + * and normalize the string according to NFKC normalization form. + */ + fun normaliseLegalName(legalName: String): String { + val trimmedLegalName = legalName.trim().replace(WHITESPACE, " ") + return Normalizer.normalize(trimmedLegalName, Normalizer.Form.NFKC) + } + + val WHITESPACE = "\\s++".toRegex() + + sealed class Rule { + companion object { + val legalNameRules: List> = listOf( + UnicodeNormalizationRule(), + CharacterRule(',', '=', '$', '"', '\'', '\\'), + WordRule("node", "server"), + LengthRule(maxLength = 255), + // TODO: Implement confusable character detection if we add more scripts. + UnicodeRangeRule(LATIN, COMMON, INHERITED), + CapitalLetterRule(), + X500NameRule(), + MustHaveAtLeastTwoLettersRule() + ) + } + + abstract fun validate(legalName: T) + + private class UnicodeNormalizationRule : Rule() { + override fun validate(legalName: String) { + require(legalName == normaliseLegalName(legalName)) { "Legal name must be normalized. Please use 'normaliseLegalName' to normalize the legal name before validation." } + } + } + + private class UnicodeRangeRule(vararg supportScripts: Character.UnicodeScript) : Rule() { + private val pattern = supportScripts.map { "\\p{Is$it}" }.joinToString(separator = "", prefix = "[", postfix = "]*").let { Pattern.compile(it) } + + override fun validate(legalName: String) { + require(pattern.matcher(legalName).matches()) { + val illegalChars = legalName.replace(pattern.toRegex(), "").toSet() + if (illegalChars.size > 1) { + "Forbidden characters $illegalChars in \"$legalName\"." + } else { + "Forbidden character $illegalChars in \"$legalName\"." + } + } + } + } + + private class CharacterRule(vararg val bannedChars: Char) : Rule() { + override fun validate(legalName: String) { + bannedChars.forEach { + require(!legalName.contains(it, true)) { "Character not allowed in legal names: $it" } + } + } + } + + private class WordRule(vararg val bannedWords: String) : Rule() { + override fun validate(legalName: String) { + bannedWords.forEach { + require(!legalName.contains(it, ignoreCase = true)) { "Word not allowed in legal names: $it" } + } + } + } + + private class LengthRule(val maxLength: Int) : Rule() { + override fun validate(legalName: String) { + require(legalName.length <= maxLength) { "Legal name longer then $maxLength characters." } + } + } + + private class CapitalLetterRule : Rule() { + override fun validate(legalName: String) { + val capitalizedLegalName = legalName.capitalize() + require(legalName == capitalizedLegalName) { "Legal name should be capitalized. i.e. '$capitalizedLegalName'" } + } + } + + private class X500NameRule : Rule() { + override fun validate(legalName: String) { + // This will throw IllegalArgumentException if the name does not comply with X500 name format. + X500Principal("CN=$legalName") + } + } + + private class MustHaveAtLeastTwoLettersRule : Rule() { + override fun validate(legalName: String) { + // Try to exclude names like "/", "£", "X" etc. + require(legalName.count { it.isLetter() } >= 2) { "Illegal input legal name '$legalName'. Legal name must have at least two letters" } + } + } + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt index 6470493af9..324d1144c7 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt @@ -2,13 +2,12 @@ package net.corda.core.messaging import net.corda.core.concurrent.CordaFuture import net.corda.core.contracts.ContractState -import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.UpgradedContract import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache @@ -21,7 +20,6 @@ import net.corda.core.node.services.vault.Sort import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.Try -import org.bouncycastle.asn1.x500.X500Name import rx.Observable import java.io.InputStream import java.security.PublicKey @@ -270,7 +268,7 @@ interface CordaRPCOps : RPCOps { /** * Returns the [Party] with the X.500 principal as it's [Party.name] */ - fun partyFromX500Name(x500Name: X500Name): Party? + fun partyFromX500Name(x500Name: CordaX500Name): Party? /** * Returns a list of candidate matches for a given string, with optional fuzzy(ish) matching. Fuzzy matching may diff --git a/core/src/main/kotlin/net/corda/core/messaging/Messaging.kt b/core/src/main/kotlin/net/corda/core/messaging/Messaging.kt index 6a18a7702b..475648d629 100644 --- a/core/src/main/kotlin/net/corda/core/messaging/Messaging.kt +++ b/core/src/main/kotlin/net/corda/core/messaging/Messaging.kt @@ -2,7 +2,6 @@ package net.corda.core.messaging import net.corda.core.serialization.CordaSerializable - /** The interface for a group of message recipients (which may contain only one recipient) */ @CordaSerializable interface MessageRecipients diff --git a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt index 322fcf3d5a..0f8d11251e 100644 --- a/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt +++ b/core/src/main/kotlin/net/corda/core/node/NodeInfo.kt @@ -6,7 +6,6 @@ import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.locality /** * Information for an advertised service including the service specific identity information. diff --git a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt index 916ef6dbe6..e45a13405e 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/IdentityService.kt @@ -1,11 +1,7 @@ package net.corda.core.node.services import net.corda.core.contracts.PartyAndReference -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate -import org.bouncycastle.asn1.x500.X500Name +import net.corda.core.identity.* import org.bouncycastle.cert.X509CertificateHolder import java.security.InvalidAlgorithmParameterException import java.security.PublicKey @@ -79,7 +75,7 @@ interface IdentityService { fun partyFromKey(key: PublicKey): Party? - fun partyFromX500Name(principal: X500Name): Party? + fun partyFromX500Name(name: CordaX500Name): Party? /** * Returns the well known identity from an abstract party. This is intended to resolve the well known identity diff --git a/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt b/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt index 3f854a44fc..7d337cd582 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt @@ -3,13 +3,13 @@ package net.corda.core.node.services import net.corda.core.concurrent.CordaFuture import net.corda.core.contracts.Contract import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.randomOrNull import net.corda.core.messaging.DataFeed import net.corda.core.node.NodeInfo import net.corda.core.serialization.CordaSerializable import net.corda.core.utilities.NetworkHostAndPort -import org.bouncycastle.asn1.x500.X500Name import rx.Observable import java.security.PublicKey @@ -77,7 +77,7 @@ interface NetworkMapCache { fun getNodeByLegalIdentity(party: AbstractParty): NodeInfo? /** Look up the node info for a legal name. */ - fun getNodeByLegalName(principal: X500Name): NodeInfo? + fun getNodeByLegalName(principal: CordaX500Name): NodeInfo? /** Look up the node info for a host and port. */ fun getNodeByAddress(address: NetworkHostAndPort): NodeInfo? @@ -100,7 +100,7 @@ interface NetworkMapCache { fun getPartyInfo(party: Party): PartyInfo? /** Gets a notary identity by the given name. */ - fun getNotary(principal: X500Name): Party? { + fun getNotary(principal: CordaX500Name): Party? { val notaryNode = notaryNodes.filter { it.advertisedServices.any { it.info.type.isSubTypeOf(ServiceType.notary) && it.info.name == principal } }.randomOrNull() diff --git a/core/src/main/kotlin/net/corda/core/node/services/ServiceInfo.kt b/core/src/main/kotlin/net/corda/core/node/services/ServiceInfo.kt index c3f1354a81..61b78aa241 100644 --- a/core/src/main/kotlin/net/corda/core/node/services/ServiceInfo.kt +++ b/core/src/main/kotlin/net/corda/core/node/services/ServiceInfo.kt @@ -1,7 +1,7 @@ package net.corda.core.node.services +import net.corda.core.identity.CordaX500Name import net.corda.core.serialization.CordaSerializable -import org.bouncycastle.asn1.x500.X500Name /** * A container for additional information for an advertised service. @@ -11,14 +11,14 @@ import org.bouncycastle.asn1.x500.X500Name * grouping identifier for nodes collectively running a distributed service. */ @CordaSerializable -data class ServiceInfo(val type: ServiceType, val name: X500Name? = null) { +data class ServiceInfo(val type: ServiceType, val name: CordaX500Name? = 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) - val principal = name?.let { X500Name(it) } + val principal = name?.let { CordaX500Name.parse(it) } return ServiceInfo(type, principal) } } diff --git a/core/src/main/kotlin/net/corda/core/utilities/LegalNameValidator.kt b/core/src/main/kotlin/net/corda/core/utilities/LegalNameValidator.kt deleted file mode 100644 index 77af8039da..0000000000 --- a/core/src/main/kotlin/net/corda/core/utilities/LegalNameValidator.kt +++ /dev/null @@ -1,170 +0,0 @@ -@file:JvmName("LegalNameValidator") - -package net.corda.core.utilities - -import org.bouncycastle.asn1.x500.X500Name -import org.bouncycastle.asn1.x500.style.BCStyle -import java.lang.Character.UnicodeScript.* -import java.text.Normalizer -import java.util.regex.Pattern -import javax.security.auth.x500.X500Principal - -/** - * The validation function will validate the input string using the following rules: - * - * - No blacklisted words like "node", "server". - * - Restrict names to Latin scripts for now to avoid right-to-left issues, debugging issues when we can't pronounce - * names over the phone, and character confusability attacks. - * - Must consist of at least three letters and should start with a capital letter. - * - No commas or equals signs. - * - No dollars or quote marks, we might need to relax the quote mark constraint in future to handle Irish company names. - * - * @throws IllegalArgumentException if the name does not meet the required rules. The message indicates why not. - */ -fun validateLegalName(normalizedLegalName: String) { - Rule.legalNameRules.forEach { it.validate(normalizedLegalName) } -} - -/** - * The normalize function will trim the input string, replace any multiple spaces with a single space, - * and normalize the string according to NFKC normalization form. - */ -fun normaliseLegalName(legalName: String): String { - val trimmedLegalName = legalName.trim().replace(WHITESPACE, " ") - return Normalizer.normalize(trimmedLegalName, Normalizer.Form.NFKC) -} - -val WHITESPACE = "\\s++".toRegex() - -private val mandatoryAttributes = setOf(BCStyle.O, BCStyle.C, BCStyle.L) -private val supportedAttributes = mandatoryAttributes + setOf(BCStyle.CN, BCStyle.ST, BCStyle.OU) - -/** - * Validate X500Name according to Corda X500Name specification - * - * Supported attributes: - * - organisation (O) – VARCHAR(127) - * - state (ST) – VARCHAR(64) nullable - * - locality (L) – VARCHAR(64) - * - country (C) – VARCHAR(2) - ISO code of the country in which it is registered - * - organizational-unit (OU) – VARCHAR(64) nullable - * - common name (CN) – VARCHAR(64) - * - * @throws IllegalArgumentException if the name does not meet the required rules. The message indicates why not. - * @see Design Doc. - */ -fun validateX500Name(x500Name: X500Name) { - val rDNs = x500Name.rdNs.flatMap { it.typesAndValues.asList() } - val attributes = rDNs.map { it.type } - - // Duplicate attribute value checks. - require(attributes.size == attributes.toSet().size) { "X500Name contain duplicate attribute." } - - // Mandatory attribute checks. - require(attributes.containsAll(mandatoryAttributes)) { - val missingAttributes = mandatoryAttributes.subtract(attributes).map { BCStyle.INSTANCE.oidToDisplayName(it) } - "The following attribute${if (missingAttributes.size > 1) "s are" else " is"} missing from the legal name : $missingAttributes" - } - - // Supported attribute checks. - require(attributes.subtract(supportedAttributes).isEmpty()) { - val unsupportedAttributes = attributes.subtract(supportedAttributes).map { BCStyle.INSTANCE.oidToDisplayName(it) } - "The following attribute${if (unsupportedAttributes.size > 1) "s are" else " is"} not supported in Corda :$unsupportedAttributes" - } - // Legal name checks. - validateLegalName(x500Name.organisation) - - // Attribute data width checks. - require(x500Name.country.length == 2) { "Invalid country '${x500Name.country}' Country code must be 2 letters ISO code " } - require(x500Name.country.toUpperCase() == x500Name.country) { "Country code should be in upper case." } - require(countryCodes.contains(x500Name.country)) { "Invalid country code '${x500Name.country}'" } - - require(x500Name.organisation.length < 128) { "Organisation attribute (O) must contain less then 128 characters." } - require(x500Name.locality.length < 64) { "Locality attribute (L) must contain less then 64 characters." } - - x500Name.state?.let { require(it.length < 64) { "State attribute (ST) must contain less then 64 characters." } } - x500Name.organisationUnit?.let { require(it.length < 64) { "Organisation Unit attribute (OU) must contain less then 64 characters." } } - x500Name.commonName?.let { require(it.length < 64) { "Common Name attribute (CN) must contain less then 64 characters." } } -} - -private sealed class Rule { - companion object { - val legalNameRules: List> = listOf( - UnicodeNormalizationRule(), - CharacterRule(',', '=', '$', '"', '\'', '\\'), - WordRule("node", "server"), - LengthRule(maxLength = 255), - // TODO: Implement confusable character detection if we add more scripts. - UnicodeRangeRule(LATIN, COMMON, INHERITED), - CapitalLetterRule(), - X500NameRule(), - MustHaveAtLeastTwoLettersRule() - ) - } - - abstract fun validate(legalName: T) - - private class UnicodeNormalizationRule : Rule() { - override fun validate(legalName: String) { - require(legalName == normaliseLegalName(legalName)) { "Legal name must be normalized. Please use 'normaliseLegalName' to normalize the legal name before validation." } - } - } - - private class UnicodeRangeRule(vararg supportScripts: Character.UnicodeScript) : Rule() { - private val pattern = supportScripts.map { "\\p{Is$it}" }.joinToString(separator = "", prefix = "[", postfix = "]*").let { Pattern.compile(it) } - - override fun validate(legalName: String) { - require(pattern.matcher(legalName).matches()) { - val illegalChars = legalName.replace(pattern.toRegex(), "").toSet() - if (illegalChars.size > 1) { - "Forbidden characters $illegalChars in \"$legalName\"." - } else { - "Forbidden character $illegalChars in \"$legalName\"." - } - } - } - } - - private class CharacterRule(vararg val bannedChars: Char) : Rule() { - override fun validate(legalName: String) { - bannedChars.forEach { - require(!legalName.contains(it, true)) { "Character not allowed in legal names: $it" } - } - } - } - - private class WordRule(vararg val bannedWords: String) : Rule() { - override fun validate(legalName: String) { - bannedWords.forEach { - require(!legalName.contains(it, ignoreCase = true)) { "Word not allowed in legal names: $it" } - } - } - } - - private class LengthRule(val maxLength: Int) : Rule() { - override fun validate(legalName: String) { - require(legalName.length <= maxLength) { "Legal name longer then $maxLength characters." } - } - } - - private class CapitalLetterRule : Rule() { - override fun validate(legalName: String) { - val capitalizedLegalName = legalName.capitalize() - require(legalName == capitalizedLegalName) { "Legal name should be capitalized. i.e. '$capitalizedLegalName'" } - } - } - - private class X500NameRule : Rule() { - override fun validate(legalName: String) { - // This will throw IllegalArgumentException if the name does not comply with X500 name format. - X500Principal("CN=$legalName") - } - } - - private class MustHaveAtLeastTwoLettersRule : Rule() { - override fun validate(legalName: String) { - // Try to exclude names like "/", "£", "X" etc. - require(legalName.count { it.isLetter() } >= 2) { "Illegal input legal name '$legalName'. Legal name must have at least two letters" } - } - } -} diff --git a/core/src/main/kotlin/net/corda/core/utilities/X500NameUtils.kt b/core/src/main/kotlin/net/corda/core/utilities/X500NameUtils.kt index dff6085f36..d141672122 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/X500NameUtils.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/X500NameUtils.kt @@ -8,7 +8,6 @@ import org.bouncycastle.asn1.x500.X500NameBuilder import org.bouncycastle.asn1.x500.style.BCStyle val X500Name.commonName: String? get() = getRDNValueString(BCStyle.CN) -val X500Name.organisationUnit: String? get() = getRDNValueString(BCStyle.OU) val X500Name.state: String? get() = getRDNValueString(BCStyle.ST) val X500Name.organisation: String get() = getRDNValueString(BCStyle.O) ?: throw IllegalArgumentException("Malformed X500 name, organisation attribute (O) cannot be empty.") val X500Name.locality: String get() = getRDNValueString(BCStyle.L) ?: throw IllegalArgumentException("Malformed X500 name, locality attribute (L) cannot be empty.") @@ -36,13 +35,4 @@ fun getX500Name(O: String, L: String, C: String, CN: String? = null, OU: String? OU?.let { addRDN(BCStyle.OU, it) } CN?.let { addRDN(BCStyle.CN, it) } }.build() -} - -fun X500Name.withCommonName(commonName: String?): X500Name { - return getX500Name(organisation, locality, country, commonName, organisationUnit, state) -} - -fun X500Name.toWellFormattedName(): X500Name { - validateX500Name(this) - return getX500Name(organisation, locality, country, commonName, organisationUnit, state) -} +} \ No newline at end of file diff --git a/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt b/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt index 873c3e5a97..95a3c4ff18 100644 --- a/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt +++ b/core/src/test/kotlin/net/corda/core/crypto/CompositeKeyTests.kt @@ -331,10 +331,10 @@ class CompositeKeyTests : TestDependencyInjectionBase() { // Create self sign CA. val caKeyPair = Crypto.generateKeyPair() - val ca = X509Utilities.createSelfSignedCACertificate(getX500Name(CN = "Test CA", O = "R3", L = "London", C = "GB"), caKeyPair) + val ca = X509Utilities.createSelfSignedCACertificate(getX500Name(CN = "Test CA", O = "R3 Ltd", L = "London", C = "GB"), caKeyPair) // Sign the composite key with the self sign CA. - val compositeKeyCert = X509Utilities.createCertificate(CertificateType.IDENTITY, ca, caKeyPair, getX500Name(CN = "CompositeKey", O = "R3", L = "London", C = "GB"), compositeKey) + val compositeKeyCert = X509Utilities.createCertificate(CertificateType.IDENTITY, ca, caKeyPair, getX500Name(CN = "CompositeKey", O = "R3 Ltd", L = "London", C = "GB"), compositeKey) // Store certificate to keystore. val keystorePath = tempFolder.root.toPath() / "keystore.jks" diff --git a/core/src/test/kotlin/net/corda/core/identity/CordaX500NameTest.kt b/core/src/test/kotlin/net/corda/core/identity/CordaX500NameTest.kt new file mode 100644 index 0000000000..e67ecd82cf --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/identity/CordaX500NameTest.kt @@ -0,0 +1,63 @@ +package net.corda.core.identity + +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNull + +class CordaX500NameTest { + @Test + fun `parse service name with organisational unit`() { + val name = CordaX500Name.parse("O=Bank A, L=New York, C=US, OU=Org Unit, CN=Service Name") + assertEquals("Service Name", name.commonName) + assertEquals("Org Unit", name.organisationUnit) + assertEquals("Bank A", name.organisation) + assertEquals("New York", name.locality) + } + + @Test + fun `parse service name`() { + val name = CordaX500Name.parse("O=Bank A, L=New York, C=US, CN=Service Name") + assertEquals("Service Name", name.commonName) + assertNull(name.organisationUnit) + assertEquals("Bank A", name.organisation) + assertEquals("New York", name.locality) + } + + @Test + fun `parse legal entity name`() { + val name = CordaX500Name.parse("O=Bank A, L=New York, C=US") + assertNull(name.commonName) + assertNull(name.organisationUnit) + assertEquals("Bank A", name.organisation) + assertEquals("New York", name.locality) + } + + @Test + fun `rejects name with no organisation`() { + assertFailsWith(IllegalArgumentException::class) { + CordaX500Name.parse("L=New York, C=US, OU=Org Unit, CN=Service Name") + } + } + + @Test + fun `rejects name with no locality`() { + assertFailsWith(IllegalArgumentException::class) { + CordaX500Name.parse("O=Bank A, C=US, OU=Org Unit, CN=Service Name") + } + } + + @Test + fun `rejects name with no country`() { + assertFailsWith(IllegalArgumentException::class) { + CordaX500Name.parse("O=Bank A, L=New York, OU=Org Unit, CN=Service Name") + } + } + + @Test + fun `rejects name with wrong organisation name format`() { + assertFailsWith(IllegalArgumentException::class) { + CordaX500Name.parse("O=B, L=New York, C=US, OU=Org Unit, CN=Service Name") + } + } +} diff --git a/core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt b/core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt index 17bfe21510..0b2c8ef51c 100644 --- a/core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt +++ b/core/src/test/kotlin/net/corda/core/identity/PartyAndCertificateTest.kt @@ -3,7 +3,6 @@ package net.corda.core.identity import net.corda.core.crypto.entropyToKeyPair import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize -import net.corda.core.utilities.getX500Name import net.corda.testing.getTestPartyAndCertificate import net.corda.testing.withTestSerialization import org.assertj.core.api.Assertions.assertThat @@ -15,7 +14,7 @@ class PartyAndCertificateTest { fun `kryo serialisation`() { withTestSerialization { val original = getTestPartyAndCertificate(Party( - getX500Name(O = "Test Corp", L = "Madrid", C = "ES"), + CordaX500Name(organisation = "Test Corp", locality = "Madrid", country = "ES"), entropyToKeyPair(BigInteger.valueOf(83)).public)) val copy = original.serialize().deserialize() assertThat(copy).isEqualTo(original).isNotSameAs(original) diff --git a/core/src/test/kotlin/net/corda/core/internal/LegalNameValidatorTest.kt b/core/src/test/kotlin/net/corda/core/internal/LegalNameValidatorTest.kt new file mode 100644 index 0000000000..0f96141922 --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/internal/LegalNameValidatorTest.kt @@ -0,0 +1,102 @@ +package net.corda.core.internal + +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +class LegalNameValidatorTest { + @Test + fun `no double spaces`() { + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("Test Legal Name") + } + LegalNameValidator.validateLegalName(LegalNameValidator.normaliseLegalName("Test Legal Name")) + } + + @Test + fun `no trailing white space`() { + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("Test ") + } + } + + @Test + fun `no prefixed white space`() { + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName(" Test") + } + } + + @Test + fun `blacklisted words`() { + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("Test Server") + } + } + + @Test + fun `blacklisted characters`() { + LegalNameValidator.validateLegalName("Test") + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("\$Test") + } + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("\"Test") + } + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("\'Test") + } + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("=Test") + } + } + + @Test + fun `unicode range`() { + LegalNameValidator.validateLegalName("Test A") + assertFailsWith(IllegalArgumentException::class) { + // Greek letter A. + LegalNameValidator.validateLegalName("Test Α") + } + } + + @Test + fun `legal name length less then 256 characters`() { + val longLegalName = StringBuilder() + while (longLegalName.length < 255) { + longLegalName.append("A") + } + LegalNameValidator.validateLegalName(longLegalName.toString()) + + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName(longLegalName.append("A").toString()) + } + } + + @Test + fun `legal name should be capitalized`() { + LegalNameValidator.validateLegalName("Good legal name") + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("bad name") + } + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("bad Name") + } + } + + @Test + fun `correctly handle whitespaces`() { + assertEquals("Legal Name With Tab", LegalNameValidator.normaliseLegalName("Legal Name With\tTab")) + assertEquals("Legal Name With Unicode Whitespaces", LegalNameValidator.normaliseLegalName("Legal Name\u2004With\u0009Unicode\u0020Whitespaces")) + assertEquals("Legal Name With Line Breaks", LegalNameValidator.normaliseLegalName("Legal Name With\n\rLine\nBreaks")) + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("Legal Name With\tTab") + } + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("Legal Name\u2004With\u0009Unicode\u0020Whitespaces") + } + assertFailsWith(IllegalArgumentException::class) { + LegalNameValidator.validateLegalName("Legal Name With\n\rLine\nBreaks") + } + } +} \ No newline at end of file diff --git a/core/src/test/kotlin/net/corda/core/node/ServiceInfoTests.kt b/core/src/test/kotlin/net/corda/core/node/ServiceInfoTests.kt index c7dfa52327..0855ee1bbf 100644 --- a/core/src/test/kotlin/net/corda/core/node/ServiceInfoTests.kt +++ b/core/src/test/kotlin/net/corda/core/node/ServiceInfoTests.kt @@ -1,15 +1,15 @@ package net.corda.core.node +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType -import net.corda.core.utilities.getX500Name import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith class ServiceInfoTests { val serviceType = ServiceType.getServiceType("test", "service").getSubType("subservice") - val name = getX500Name(O = "service.name", L = "London", C = "GB") + val name = CordaX500Name(organisation = "Service.name", locality = "London", country = "GB") @Test fun `type and name encodes correctly`() { diff --git a/core/src/test/kotlin/net/corda/core/utilities/LegalNameValidatorTest.kt b/core/src/test/kotlin/net/corda/core/utilities/LegalNameValidatorTest.kt deleted file mode 100644 index 163381ca69..0000000000 --- a/core/src/test/kotlin/net/corda/core/utilities/LegalNameValidatorTest.kt +++ /dev/null @@ -1,132 +0,0 @@ -package net.corda.core.utilities - -import org.bouncycastle.asn1.x500.X500Name -import org.junit.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - -class LegalNameValidatorTest { - @Test - fun `no double spaces`() { - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("Test Legal Name") - } - validateLegalName(normaliseLegalName("Test Legal Name")) - } - - @Test - fun `no trailing white space`() { - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("Test ") - } - } - - @Test - fun `no prefixed white space`() { - assertFailsWith(IllegalArgumentException::class) { - validateLegalName(" Test") - } - } - - @Test - fun `blacklisted words`() { - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("Test Server") - } - } - - @Test - fun `blacklisted characters`() { - validateLegalName("Test") - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("\$Test") - } - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("\"Test") - } - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("\'Test") - } - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("=Test") - } - } - - @Test - fun `unicode range`() { - validateLegalName("Test A") - assertFailsWith(IllegalArgumentException::class) { - // Greek letter A. - validateLegalName("Test Α") - } - } - - @Test - fun `legal name length less then 256 characters`() { - val longLegalName = StringBuilder() - while (longLegalName.length < 255) { - longLegalName.append("A") - } - validateLegalName(longLegalName.toString()) - - assertFailsWith(IllegalArgumentException::class) { - validateLegalName(longLegalName.append("A").toString()) - } - } - - @Test - fun `legal name should be capitalized`() { - validateLegalName("Good legal name") - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("bad name") - } - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("bad Name") - } - } - - @Test - fun `correctly handle whitespaces`() { - assertEquals("Legal Name With Tab", normaliseLegalName("Legal Name With\tTab")) - assertEquals("Legal Name With Unicode Whitespaces", normaliseLegalName("Legal Name\u2004With\u0009Unicode\u0020Whitespaces")) - assertEquals("Legal Name With Line Breaks", normaliseLegalName("Legal Name With\n\rLine\nBreaks")) - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("Legal Name With\tTab") - } - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("Legal Name\u2004With\u0009Unicode\u0020Whitespaces") - } - assertFailsWith(IllegalArgumentException::class) { - validateLegalName("Legal Name With\n\rLine\nBreaks") - } - } - - @Test - fun `validate x500Name`() { - validateX500Name(X500Name("O=Bank A, L=New York, C=US, OU=Org Unit, CN=Service Name")) - validateX500Name(X500Name("O=Bank A, L=New York, C=US, CN=Service Name")) - validateX500Name(X500Name("O=Bank A, L=New York, C=US")) - validateX500Name(X500Name("O=Bank A, L=New York, C=US")) - - // Missing Organisation - assertFailsWith(IllegalArgumentException::class) { - validateX500Name(X500Name("L=New York, C=US, OU=Org Unit, CN=Service Name")) - } - // Missing Locality - assertFailsWith(IllegalArgumentException::class) { - validateX500Name(X500Name("O=Bank A, C=US, OU=Org Unit, CN=Service Name")) - } - // Missing Country - assertFailsWith(IllegalArgumentException::class) { - validateX500Name(X500Name("O=Bank A, L=New York, OU=Org Unit, CN=Service Name")) - } - // Wrong organisation name format - assertFailsWith(IllegalArgumentException::class) { - validateX500Name(X500Name("O=B, L=New York, C=US, OU=Org Unit, CN=Service Name")) - } - // Wrong organisation name format - assertFailsWith(IllegalArgumentException::class) { - validateX500Name(X500Name("O=B, L=New York, C=US, OU=Org Unit, CN=Service Name")) - } - } -} \ No newline at end of file diff --git a/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java b/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java index a7caceebba..1be5dbc965 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java @@ -7,6 +7,7 @@ import net.corda.core.contracts.*; import net.corda.core.crypto.SecureHash; import net.corda.core.crypto.TransactionSignature; import net.corda.core.flows.*; +import net.corda.core.identity.CordaX500Name; import net.corda.core.identity.Party; import net.corda.core.internal.FetchDataFlow; import net.corda.core.node.services.ServiceType; @@ -19,7 +20,6 @@ import net.corda.core.transactions.TransactionBuilder; import net.corda.core.utilities.ProgressTracker; import net.corda.core.utilities.ProgressTracker.Step; import net.corda.core.utilities.UntrustworthyData; -import net.corda.core.utilities.X500NameUtils; import net.corda.finance.contracts.asset.Cash; import net.corda.testing.contracts.DummyContract; import net.corda.testing.contracts.DummyContractKt; @@ -123,7 +123,7 @@ public class FlowCookbookJava { // - To serve as a timestamping authority if the transaction has a time-window // We retrieve a notary from the network map. // DOCSTART 1 - Party specificNotary = getServiceHub().getNetworkMapCache().getNotary(X500NameUtils.getX500Name("Notary Service", "London", "UK")); + Party specificNotary = getServiceHub().getNetworkMapCache().getNotary(new CordaX500Name("Notary Service", "London", "UK")); Party anyNotary = getServiceHub().getNetworkMapCache().getAnyNotary(null); // Unlike the first two methods, ``getNotaryNodes`` returns a // ``List``. We have to extract the notary identity of @@ -134,7 +134,7 @@ public class FlowCookbookJava { // We may also need to identify a specific counterparty. // Again, we do so using the network map. // DOCSTART 2 - Party namedCounterparty = getServiceHub().getNetworkMapCache().getNodeByLegalName(X500NameUtils.getX500Name("NodeA", "London", "UK")).getLegalIdentity(); + Party namedCounterparty = getServiceHub().getNetworkMapCache().getNodeByLegalName(new CordaX500Name("NodeA", "London", "UK")).getLegalIdentity(); Party keyedCounterparty = getServiceHub().getNetworkMapCache().getNodeByLegalIdentityKey(dummyPubKey).getLegalIdentity(); Party firstCounterparty = getServiceHub().getNetworkMapCache().getPartyNodes().get(0).getLegalIdentity(); // DOCEND 2 diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt index daff7ec006..c7292a6f8a 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt @@ -7,6 +7,7 @@ import net.corda.core.contracts.* import net.corda.core.crypto.SecureHash import net.corda.core.crypto.TransactionSignature import net.corda.core.flows.* +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.FetchDataFlow import net.corda.core.node.services.ServiceType @@ -103,7 +104,7 @@ object FlowCookbook { // - To serve as a timestamping authority if the transaction has a time-window // We retrieve the notary from the network map. // DOCSTART 1 - val specificNotary: Party? = serviceHub.networkMapCache.getNotary(getX500Name(O = "Notary Service", OU = "corda", L = "London", C = "UK")) + val specificNotary: Party? = serviceHub.networkMapCache.getNotary(CordaX500Name(organisation = "Notary Service", locality = "London", country = "UK")) val anyNotary: Party? = serviceHub.networkMapCache.getAnyNotary() // Unlike the first two methods, ``getNotaryNodes`` returns a // ``List``. We have to extract the notary identity of @@ -114,7 +115,7 @@ object FlowCookbook { // We may also need to identify a specific counterparty. Again, we // do so using the network map. // DOCSTART 2 - val namedCounterparty: Party? = serviceHub.networkMapCache.getNodeByLegalName(getX500Name(O = "NodeA", L = "London", C = "UK"))?.legalIdentity + val namedCounterparty: Party? = serviceHub.networkMapCache.getNodeByLegalName(CordaX500Name(organisation = "NodeA", locality = "London", country = "UK"))?.legalIdentity val keyedCounterparty: Party? = serviceHub.networkMapCache.getNodeByLegalIdentityKey(dummyPubKey)?.legalIdentity val firstCounterparty: Party = serviceHub.networkMapCache.partyNodes[0].legalIdentity // DOCEND 2 diff --git a/finance/src/main/kotlin/net/corda/finance/contracts/asset/Cash.kt b/finance/src/main/kotlin/net/corda/finance/contracts/asset/Cash.kt index 69b2c937f2..b91ee06eeb 100644 --- a/finance/src/main/kotlin/net/corda/finance/contracts/asset/Cash.kt +++ b/finance/src/main/kotlin/net/corda/finance/contracts/asset/Cash.kt @@ -9,6 +9,7 @@ import net.corda.core.contracts.Amount.Companion.sumOrThrow import net.corda.core.crypto.NullKeys.NULL_PARTY import net.corda.core.crypto.entropyToKeyPair import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.Emoji import net.corda.core.node.ServiceHub @@ -18,7 +19,6 @@ import net.corda.core.schemas.QueryableState import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.OpaqueBytes -import net.corda.core.utilities.getX500Name import net.corda.core.utilities.toBase58String import net.corda.finance.contracts.asset.cash.selection.CashSelectionH2Impl import net.corda.finance.schemas.CashSchemaV1 @@ -346,7 +346,7 @@ class Cash : OnLedgerAsset() { /** A randomly generated key. */ val DUMMY_CASH_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) } /** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */ -val DUMMY_CASH_ISSUER by lazy { Party(getX500Name(O = "Snake Oil Issuer", OU = "corda", L = "London", C = "GB"), DUMMY_CASH_ISSUER_KEY.public).ref(1) } +val DUMMY_CASH_ISSUER by lazy { Party(CordaX500Name(organisation = "Snake Oil Issuer", locality = "London", country = "GB"), DUMMY_CASH_ISSUER_KEY.public).ref(1) } /** An extension property that lets you write 100.DOLLARS.CASH */ val Amount.CASH: Cash.State get() = Cash.State(Amount(quantity, Issued(DUMMY_CASH_ISSUER, token)), NULL_PARTY) /** An extension property that lets you get a cash state from an issued token, under the [NULL_PARTY] */ diff --git a/finance/src/main/kotlin/net/corda/finance/contracts/asset/Obligation.kt b/finance/src/main/kotlin/net/corda/finance/contracts/asset/Obligation.kt index 609d0c1479..b80a30c0aa 100644 --- a/finance/src/main/kotlin/net/corda/finance/contracts/asset/Obligation.kt +++ b/finance/src/main/kotlin/net/corda/finance/contracts/asset/Obligation.kt @@ -9,6 +9,7 @@ import net.corda.core.crypto.SecureHash import net.corda.core.crypto.entropyToKeyPair import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.Emoji import net.corda.core.internal.VisibleForTesting @@ -16,7 +17,6 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.NonEmptySet -import net.corda.core.utilities.getX500Name import net.corda.core.utilities.seconds import net.corda.finance.utils.sumFungibleOrNull import net.corda.finance.utils.sumObligations @@ -792,4 +792,4 @@ infix fun Obligation.State.`issued by`(party: AbstractParty) = copy /** A randomly generated key. */ val DUMMY_OBLIGATION_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) } /** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */ -val DUMMY_OBLIGATION_ISSUER by lazy { Party(getX500Name(O = "Snake Oil Issuer", OU = "corda", L = "London", C = "GB"), DUMMY_OBLIGATION_ISSUER_KEY.public) } +val DUMMY_OBLIGATION_ISSUER by lazy { Party(CordaX500Name(organisation = "Snake Oil Issuer", locality = "London", country = "GB"), DUMMY_OBLIGATION_ISSUER_KEY.public) } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt b/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt index 5cda03946f..4e2f5aa690 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/ArtemisTcpTransport.kt @@ -1,5 +1,6 @@ package net.corda.nodeapi +import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.config.SSLConfiguration import org.apache.activemq.artemis.api.core.TransportConfiguration @@ -12,7 +13,7 @@ import java.nio.file.Path sealed class ConnectionDirection { data class Inbound(val acceptorFactoryClassName: String) : ConnectionDirection() data class Outbound( - val expectedCommonName: X500Name? = null, + val expectedCommonName: CordaX500Name? = null, val connectorFactoryClassName: String = NettyConnectorFactory::class.java.name ) : ConnectionDirection() } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt index 20f8fb8513..e8108aacf3 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/config/ConfigUtilities.kt @@ -2,10 +2,10 @@ package net.corda.nodeapi.config import com.typesafe.config.Config import com.typesafe.config.ConfigUtil +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.noneOrSingle import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.parseNetworkHostAndPort -import org.bouncycastle.asn1.x500.X500Name import org.slf4j.LoggerFactory import java.net.Proxy import java.net.URL @@ -72,7 +72,7 @@ private fun Config.getSingleValue(path: String, type: KType): Any? { Path::class -> Paths.get(getString(path)) URL::class -> URL(getString(path)) Properties::class -> getConfig(path).toProperties() - X500Name::class -> X500Name(getString(path)) + CordaX500Name::class -> CordaX500Name.parse(getString(path)) else -> if (typeClass.java.isEnum) { parseEnum(typeClass.java, getString(path)) } else { @@ -99,7 +99,7 @@ private fun Config.getCollectionValue(path: String, type: KType): Collection getStringList(path).map { it.parseNetworkHostAndPort() } Path::class -> getStringList(path).map { Paths.get(it) } URL::class -> getStringList(path).map(::URL) - X500Name::class -> getStringList(path).map(::X500Name) + CordaX500Name::class -> getStringList(path).map(CordaX500Name.Companion::parse) Properties::class -> getConfigList(path).map(Config::toProperties) else -> if (elementClass.java.isEnum) { getStringList(path).map { parseEnum(elementClass.java, it) } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt index 7264d57b5c..e13c47ce05 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/config/ConfigParsingTest.kt @@ -4,11 +4,10 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigFactory.empty import com.typesafe.config.ConfigRenderOptions.defaults import com.typesafe.config.ConfigValueFactory +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getX500Name 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 @@ -112,7 +111,7 @@ class ConfigParsingTest { @Test fun x500Name() { - testPropertyType(getX500Name(O = "Mock Party", L = "London", C = "GB"), getX500Name(O = "Mock Party 2", L = "London", C = "GB"), valuesToString = true) + testPropertyType(CordaX500Name(organisation = "Mock Party", locality = "London", country = "GB"), CordaX500Name(organisation = "Mock Party 2", locality = "London", country = "GB"), valuesToString = true) } @Test @@ -229,8 +228,8 @@ class ConfigParsingTest { data class PathListData(override val values: List) : ListData data class URLData(override val value: URL) : SingleData data class URLListData(override val values: List) : ListData - data class X500NameData(override val value: X500Name) : SingleData - data class X500NameListData(override val values: List) : ListData + data class X500NameData(override val value: CordaX500Name) : SingleData + data class X500NameListData(override val values: List) : ListData data class PropertiesData(override val value: Properties) : SingleData data class PropertiesListData(override val values: List) : ListData data class MultiPropertyData(val i: Int, val b: Boolean, val l: List) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/AdvertisedServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/AdvertisedServiceTests.kt index 55a7ac3bf0..d11c58052b 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/AdvertisedServiceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/AdvertisedServiceTests.kt @@ -3,10 +3,10 @@ package net.corda.node.services import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC +import net.corda.core.identity.CordaX500Name import net.corda.core.messaging.startFlow import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType -import net.corda.core.utilities.getX500Name import net.corda.node.services.FlowPermissions.Companion.startFlowPermission import net.corda.nodeapi.User import net.corda.testing.driver.driver @@ -14,7 +14,7 @@ import org.junit.Test import kotlin.test.assertTrue class AdvertisedServiceTests { - private val serviceName = getX500Name(O = "Custom Service", OU = "corda", L = "London", C = "GB") + private val serviceName = CordaX500Name(organisation = "Custom Service", locality = "London", country = "GB") private val serviceType = ServiceType.corda.getSubType("custom") private val user = "bankA" private val pass = "passA" diff --git a/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt index 211bc84fb2..c651218abf 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/BFTNotaryServiceTests.kt @@ -7,6 +7,7 @@ import net.corda.core.crypto.CompositeKey import net.corda.core.flows.NotaryError import net.corda.core.flows.NotaryException import net.corda.core.flows.NotaryFlow +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.div import net.corda.core.node.services.ServiceInfo @@ -15,7 +16,6 @@ import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.Try import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.getX500Name import net.corda.node.internal.AbstractNode import net.corda.node.services.config.BFTSMaRtConfiguration import net.corda.node.services.network.NetworkMapService @@ -35,7 +35,7 @@ import kotlin.test.assertTrue class BFTNotaryServiceTests { companion object { - private val clusterName = getX500Name(O = "BFT", OU = "corda", L = "Zurich", C = "CH") + private val clusterName = CordaX500Name(organisation = "BFT", locality = "Zurich", country = "CH") private val serviceType = BFTNonValidatingNotaryService.type } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt b/node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt index 76ba4ae494..45221d65c9 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/RaftNotaryServiceTests.kt @@ -5,12 +5,12 @@ import net.corda.core.contracts.StateRef import net.corda.core.flows.NotaryError import net.corda.core.flows.NotaryException import net.corda.core.flows.NotaryFlow +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.concurrent.map import net.corda.core.internal.concurrent.transpose import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.getX500Name import net.corda.node.internal.AbstractNode import net.corda.testing.DUMMY_BANK_A import net.corda.testing.contracts.DUMMY_PROGRAM_ID @@ -23,7 +23,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith class RaftNotaryServiceTests : NodeBasedTest() { - private val notaryName = getX500Name(O = "RAFT Notary Service", OU = "corda", L = "London", C = "GB") + private val notaryName = CordaX500Name(organisation = "RAFT Notary Service", locality = "London", country = "GB") @Test fun `detect double spend`() { diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt index d053552c1c..b5a42ecfba 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/MQSecurityAsNodeTest.kt @@ -103,7 +103,7 @@ class MQSecurityAsNodeTest : MQSecurityTest() { val clientKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) // Set name constrain to the legal name. - val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName))), arrayOf()) + val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, legalName.x500Name))), arrayOf()) val clientCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, intermediateCA.certificate, intermediateCA.keyPair, legalName, clientKey.public, nameConstraints = nameConstraints) val tlsKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt index dd79a907f8..b10d05f4e4 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PMessagingTest.kt @@ -2,6 +2,7 @@ package net.corda.services.messaging import net.corda.core.concurrent.CordaFuture import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.elapsedTime import net.corda.core.internal.times @@ -12,7 +13,6 @@ import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.getX500Name import net.corda.core.utilities.seconds import net.corda.node.internal.Node import net.corda.node.services.messaging.* @@ -22,7 +22,6 @@ import net.corda.node.utilities.ServiceIdentityGenerator import net.corda.testing.* import net.corda.testing.node.NodeBasedTest import org.assertj.core.api.Assertions.assertThat -import org.bouncycastle.asn1.x500.X500Name import org.junit.Test import java.util.* import java.util.concurrent.CountDownLatch @@ -31,8 +30,8 @@ import java.util.concurrent.atomic.AtomicInteger class P2PMessagingTest : NodeBasedTest() { private companion object { - val DISTRIBUTED_SERVICE_NAME = getX500Name(O = "DistributedService", L = "London", C = "GB") - val SERVICE_2_NAME = getX500Name(O = "Service 2", L = "London", C = "GB") + val DISTRIBUTED_SERVICE_NAME = CordaX500Name(organisation = "DistributedService", locality = "London", country = "GB") + val SERVICE_2_NAME = CordaX500Name(organisation = "Service 2", locality = "London", country = "GB") } @Test @@ -65,7 +64,7 @@ class P2PMessagingTest : NodeBasedTest() { @Test fun `communicating with a distributed service which the network map node is part of`() { ServiceIdentityGenerator.generateToDisk( - listOf(DUMMY_MAP.name, SERVICE_2_NAME).map { baseDirectory(it) }, + listOf(DUMMY_MAP.name, SERVICE_2_NAME).map { baseDirectory(it.x500Name) }, RaftValidatingNotaryService.type.id, DISTRIBUTED_SERVICE_NAME) @@ -204,7 +203,7 @@ class P2PMessagingTest : NodeBasedTest() { return crashingNodes } - private fun assertAllNodesAreUsed(participatingServiceNodes: List, serviceName: X500Name, originatingNode: Node) { + private fun assertAllNodesAreUsed(participatingServiceNodes: List, serviceName: CordaX500Name, originatingNode: Node) { // Setup each node in the distributed service to return back it's NodeInfo so that we can know which node is being used participatingServiceNodes.forEach { node -> node.respondWith(node.info) diff --git a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt index 76918e4a74..e743329824 100644 --- a/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt +++ b/node/src/integration-test/kotlin/net/corda/services/messaging/P2PSecurityTest.kt @@ -3,6 +3,7 @@ package net.corda.services.messaging import com.nhaarman.mockito_kotlin.whenever import net.corda.core.concurrent.CordaFuture import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.node.NodeInfo import net.corda.core.utilities.* import net.corda.node.internal.NetworkMapInfo @@ -17,7 +18,6 @@ import net.corda.testing.node.NodeBasedTest import net.corda.testing.node.SimpleNode import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatThrownBy -import org.bouncycastle.asn1.x500.X500Name import org.junit.Test import java.security.cert.X509Certificate import java.time.Instant @@ -51,10 +51,10 @@ class P2PSecurityTest : NodeBasedTest() { } } - private fun startSimpleNode(legalName: X500Name, + private fun startSimpleNode(legalName: CordaX500Name, trustRoot: X509Certificate): SimpleNode { val config = testNodeConfiguration( - baseDirectory = baseDirectory(legalName), + baseDirectory = baseDirectory(legalName.x500Name), myLegalName = legalName).also { whenever(it.networkMapService).thenReturn(NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name)) } @@ -62,7 +62,7 @@ class P2PSecurityTest : NodeBasedTest() { return SimpleNode(config, trustRoot = trustRoot).apply { start() } } - private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): CordaFuture { + private fun SimpleNode.registerWithNetworkMap(registrationName: CordaX500Name): CordaFuture { val legalIdentity = getTestPartyAndCertificate(registrationName, identity.public) val nodeInfo = NodeInfo(listOf(MOCK_HOST_AND_PORT), legalIdentity, NonEmptySet.of(legalIdentity), 1, serial = 1) val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX) diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index d2e7c742fc..41ef04ce39 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -10,6 +10,7 @@ import net.corda.core.concurrent.CordaFuture import net.corda.core.crypto.* import net.corda.core.flows.* import net.corda.core.flows.ContractUpgradeFlow.Acceptor +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.* @@ -28,7 +29,9 @@ import net.corda.core.node.services.NetworkMapCache.MapChange import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.SignedTransaction -import net.corda.core.utilities.* +import net.corda.core.utilities.NetworkHostAndPort +import net.corda.core.utilities.cert +import net.corda.core.utilities.debug import net.corda.node.services.NotaryChangeHandler import net.corda.node.services.NotifyTransactionHandler import net.corda.node.services.TransactionKeyHandler @@ -65,7 +68,6 @@ import net.corda.node.services.vault.VaultSoftLockManager import net.corda.node.utilities.* import net.corda.node.utilities.AddOrRemove.ADD import org.apache.activemq.artemis.utils.ReusableLatch -import org.bouncycastle.asn1.x500.X500Name import org.slf4j.Logger import rx.Observable import java.io.IOException @@ -148,8 +150,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val nodeReadyFuture: CordaFuture get() = _nodeReadyFuture - protected val myLegalName: X500Name by lazy { - loadKeyStore(configuration.nodeKeystore, configuration.keyStorePassword).getX509Certificate(X509Utilities.CORDA_CLIENT_CA).subject.withCommonName(null) + protected val myLegalName: CordaX500Name by lazy { + val cert = loadKeyStore(configuration.nodeKeystore, configuration.keyStorePassword).getX509Certificate(X509Utilities.CORDA_CLIENT_CA) + CordaX500Name.build(cert.subject).copy(commonName = null) } /** Fetch CordaPluginRegistry classes registered in META-INF/services/net.corda.core.node.CordaPluginRegistry files that exist in the classpath */ @@ -693,9 +696,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val (id, name) = if (serviceInfo == null) { // Create node identity if service info = null - Pair("identity", myLegalName.withCommonName(null)) + Pair("identity", myLegalName.copy(commonName = null)) } else { - val name = serviceInfo.name ?: myLegalName.withCommonName(serviceInfo.type.id) + val name = serviceInfo.name ?: myLegalName.copy(commonName = serviceInfo.type.id) Pair(serviceInfo.type.id, name) } @@ -735,14 +738,14 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, } val subject = certificates[0].toX509CertHolder().subject - if (subject != name) + if (subject != name.x500Name) throw ConfigurationException("The name for $id doesn't match what's in the key store: $name vs $subject") partyKeys += keys return PartyAndCertificate(CertificateFactory.getInstance("X509").generateCertPath(certificates)) } - private fun migrateKeysFromFile(keyStore: KeyStoreWrapper, serviceName: X500Name, + private fun migrateKeysFromFile(keyStore: KeyStoreWrapper, serviceName: CordaX500Name, pubKeyFile: Path, privKeyFile: Path, compositeKeyFile:Path, privateKeyAlias: String, compositeKeyAlias: String) { log.info("Migrating $privateKeyAlias from file to key store...") diff --git a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt index 550e22f791..bf09087453 100644 --- a/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/CordaRPCOpsImpl.kt @@ -3,13 +3,12 @@ package net.corda.node.internal import net.corda.client.rpc.notUsed import net.corda.core.concurrent.CordaFuture import net.corda.core.contracts.ContractState -import net.corda.core.contracts.StateAndRef -import net.corda.core.contracts.UpgradedContract import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowInitiator import net.corda.core.flows.FlowLogic import net.corda.core.flows.StartableByRPC import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.messaging.* import net.corda.core.node.NodeInfo @@ -26,7 +25,6 @@ import net.corda.node.services.messaging.requirePermission import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.utilities.CordaPersistence -import org.bouncycastle.asn1.x500.X500Name import rx.Observable import java.io.InputStream import java.security.PublicKey @@ -191,7 +189,7 @@ class CordaRPCOpsImpl( } } - override fun partyFromX500Name(x500Name: X500Name): Party? { + override fun partyFromX500Name(x500Name: CordaX500Name): Party? { return database.transaction { services.identityService.partyFromX500Name(x500Name) } diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 27e67ec30d..9c69148450 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -2,6 +2,7 @@ package net.corda.node.internal import com.codahale.metrics.JmxReporter import net.corda.core.concurrent.CordaFuture +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.concurrent.doneFuture import net.corda.core.internal.concurrent.flatMap @@ -39,7 +40,6 @@ import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException import org.apache.activemq.artemis.api.core.RoutingType import org.apache.activemq.artemis.api.core.client.ActiveMQClient import org.apache.activemq.artemis.api.core.client.ClientMessage -import org.bouncycastle.asn1.x500.X500Name import org.slf4j.Logger import org.slf4j.LoggerFactory import java.io.IOException @@ -378,4 +378,4 @@ open class Node(override val configuration: FullNodeConfiguration, class ConfigurationException(message: String) : Exception(message) -data class NetworkMapInfo(val address: NetworkHostAndPort, val legalName: X500Name) +data class NetworkMapInfo(val address: NetworkHostAndPort, val legalName: CordaX500Name) diff --git a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt index b070bc3565..d7feadc2a1 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/ConfigUtilities.kt @@ -6,16 +6,14 @@ import com.typesafe.config.ConfigParseOptions import com.typesafe.config.ConfigRenderOptions import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignatureScheme +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.copyTo import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.internal.exists import net.corda.core.utilities.loggerFor -import net.corda.core.utilities.toWellFormattedName -import net.corda.core.utilities.withCommonName import net.corda.node.utilities.* import net.corda.nodeapi.config.SSLConfiguration -import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x509.GeneralName import org.bouncycastle.asn1.x509.GeneralSubtree import org.bouncycastle.asn1.x509.NameConstraints @@ -53,7 +51,7 @@ object ConfigHelper { */ fun NodeConfiguration.configureWithDevSSLCertificate() = configureDevKeyAndTrustStores(myLegalName) -fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: X500Name) { +fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500Name) { certificatesDirectory.createDirectories() if (!trustStoreFile.exists()) { javaClass.classLoader.getResourceAsStream("net/corda/node/internal/certificates/cordatruststore.jks").copyTo(trustStoreFile) @@ -81,25 +79,25 @@ fun createKeystoreForCordaNode(sslKeyStorePath: Path, keyPassword: String, caKeyStore: KeyStore, caKeyPassword: String, - legalName: X500Name, + legalName: CordaX500Name, signatureScheme: SignatureScheme = X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) { val rootCACert = caKeyStore.getX509Certificate(X509Utilities.CORDA_ROOT_CA) val (intermediateCACert, intermediateCAKeyPair) = caKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_INTERMEDIATE_CA, caKeyPassword) val clientKey = Crypto.generateKeyPair(signatureScheme) - val clientName = legalName.toWellFormattedName().withCommonName(null) + val clientName = legalName.copy(commonName = null) - val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, clientName))), arrayOf()) + val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, clientName.x500Name))), arrayOf()) val clientCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, intermediateCACert, intermediateCAKeyPair, - clientName.withCommonName(X509Utilities.CORDA_CLIENT_CA_CN), + clientName.copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN).x500Name, clientKey.public, nameConstraints = nameConstraints) val tlsKey = Crypto.generateKeyPair(signatureScheme) - val clientTLSCert = X509Utilities.createCertificate(CertificateType.TLS, clientCACert, clientKey, clientName, tlsKey.public) + val clientTLSCert = X509Utilities.createCertificate(CertificateType.TLS, clientCACert, clientKey, clientName.x500Name, tlsKey.public) val keyPass = keyPassword.toCharArray() @@ -118,4 +116,4 @@ fun createKeystoreForCordaNode(sslKeyStorePath: Path, keyPass, arrayOf(clientTLSCert, clientCACert, intermediateCACert, rootCACert)) tlsKeystore.save(sslKeyStorePath, storePassword) -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index f884d8b31e..37bea1cae9 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -1,5 +1,6 @@ package net.corda.node.services.config +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.ServiceInfo import net.corda.core.utilities.NetworkHostAndPort import net.corda.node.internal.NetworkMapInfo @@ -8,7 +9,6 @@ import net.corda.node.services.network.NetworkMapService import net.corda.nodeapi.User import net.corda.nodeapi.config.NodeSSLConfiguration import net.corda.nodeapi.config.OldConfig -import org.bouncycastle.asn1.x500.X500Name import java.net.URL import java.nio.file.Path import java.util.* @@ -21,7 +21,7 @@ data class BFTSMaRtConfiguration(val replicaId: Int, val debug: Boolean, val exp interface NodeConfiguration : NodeSSLConfiguration { // myLegalName should be only used in the initial network registration, we should use the name from the certificate instead of this. // TODO: Remove this so we don't accidentally use this identity in the code? - val myLegalName: X500Name + val myLegalName: CordaX500Name val networkMapService: NetworkMapInfo? val minimumPlatformVersion: Int val emailAddress: String @@ -42,10 +42,10 @@ interface NodeConfiguration : NodeSSLConfiguration { data class FullNodeConfiguration( // TODO Remove this subsitution value and use baseDirectory as the subsitution instead @Deprecated( - "This is a subsitution value which points to the baseDirectory and is manually added into the config before parsing", + "This is a substitution value which points to the baseDirectory and is manually added into the config before parsing", ReplaceWith("baseDirectory")) val basedir: Path, - override val myLegalName: X500Name, + override val myLegalName: CordaX500Name, override val emailAddress: String, override val keyStorePassword: String, override val trustStorePassword: String, diff --git a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt index 312d5895ee..a730e4bf68 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/InMemoryIdentityService.kt @@ -2,10 +2,7 @@ package net.corda.node.services.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.crypto.toStringShort -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.* import net.corda.core.internal.toX509CertHolder import net.corda.core.node.services.IdentityService import net.corda.core.node.services.UnknownAnonymousPartyException @@ -14,7 +11,6 @@ import net.corda.core.utilities.cert import net.corda.core.utilities.loggerFor import net.corda.core.utilities.subject import net.corda.core.utilities.trace -import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.security.InvalidAlgorithmParameterException import java.security.PublicKey @@ -46,7 +42,7 @@ class InMemoryIdentityService(identities: Iterable = emptyS override val trustRootHolder = trustRoot.toX509CertHolder() override val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null) private val keyToParties = ConcurrentHashMap() - private val principalToParties = ConcurrentHashMap() + private val principalToParties = ConcurrentHashMap() init { val caCertificatesWithRoot: Set = caCertificates.toSet() + trustRoot @@ -91,7 +87,7 @@ class InMemoryIdentityService(identities: Iterable = emptyS override fun getAllIdentities(): Iterable = ArrayList(keyToParties.values) override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party - override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]?.party + override fun partyFromX500Name(name: CordaX500Name): Party? = principalToParties[name]?.party override fun partyFromAnonymous(party: AbstractParty): Party? { // Expand the anonymous party to a full party (i.e. has a name) if possible val candidate = party as? Party ?: keyToParties[party.owningKey]?.party @@ -114,7 +110,7 @@ class InMemoryIdentityService(identities: Iterable = emptyS val results = LinkedHashSet() for ((x500name, partyAndCertificate) in principalToParties) { val party = partyAndCertificate.party - for (rdn in x500name.rdNs) { + for (rdn in x500name.x500Name.rdNs) { val component = rdn.first.value.toString() if (exactMatch && component == query) { results += party diff --git a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt index 6774883ab9..ddca1ffaee 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt @@ -3,10 +3,7 @@ package net.corda.node.services.identity import net.corda.core.contracts.PartyAndReference import net.corda.core.crypto.SecureHash import net.corda.core.crypto.toStringShort -import net.corda.core.identity.AbstractParty -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.Party -import net.corda.core.identity.PartyAndCertificate +import net.corda.core.identity.* import net.corda.core.internal.toX509CertHolder import net.corda.core.node.services.IdentityService import net.corda.core.node.services.UnknownAnonymousPartyException @@ -15,7 +12,6 @@ import net.corda.core.utilities.cert import net.corda.core.utilities.loggerFor import net.corda.node.utilities.AppendOnlyPersistentMap import net.corda.node.utilities.NODE_DATABASE_PREFIX -import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.io.ByteArrayInputStream import java.security.InvalidAlgorithmParameterException @@ -56,11 +52,11 @@ class PersistentIdentityService(identities: Iterable = empt ) } - fun createX500Map(): AppendOnlyPersistentMap { + fun createX500Map(): AppendOnlyPersistentMap { return AppendOnlyPersistentMap( toPersistentEntityKey = { it.toString() }, - fromPersistentEntity = { Pair(X500Name(it.name), SecureHash.parse(it.publicKeyHash)) }, - toPersistentEntity = { key: X500Name, value: SecureHash -> + fromPersistentEntity = { Pair(CordaX500Name.parse(it.name), SecureHash.parse(it.publicKeyHash)) }, + toPersistentEntity = { key: CordaX500Name, value: SecureHash -> PersistentIdentityNames(key.toString(), value.toString()) }, persistentEntityClass = PersistentIdentityNames::class.java @@ -134,20 +130,20 @@ class PersistentIdentityService(identities: Iterable = empt } override fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = keyToParties[mapToKey(owningKey)] - private fun certificateFromX500Name(name: X500Name): PartyAndCertificate? { + private fun certificateFromCordaX500Name(name: CordaX500Name): PartyAndCertificate? { val partyId = principalToParties[name] return if (partyId != null) { keyToParties[partyId] } else null } - override fun certificateFromParty(party: Party): PartyAndCertificate = certificateFromX500Name(party.name) ?: throw IllegalArgumentException("Unknown identity ${party.name}") + override fun certificateFromParty(party: Party): PartyAndCertificate = certificateFromCordaX500Name(party.name) ?: throw IllegalArgumentException("Unknown identity ${party.name}") // We give the caller a copy of the data set to avoid any locking problems override fun getAllIdentities(): Iterable = keyToParties.allPersisted().map { it.second }.asIterable() override fun partyFromKey(key: PublicKey): Party? = certificateFromKey(key)?.party - override fun partyFromX500Name(principal: X500Name): Party? = certificateFromX500Name(principal)?.party + override fun partyFromX500Name(name: CordaX500Name): Party? = certificateFromCordaX500Name(name)?.party override fun partyFromAnonymous(party: AbstractParty): Party? { // Expand the anonymous party to a full party (i.e. has a name) if possible val candidate = party as? Party ?: partyFromKey(party.owningKey) @@ -172,7 +168,7 @@ class PersistentIdentityService(identities: Iterable = empt val results = LinkedHashSet() for ((x500name, partyId) in principalToParties.allPersisted()) { val party = keyToParties[partyId]!!.party - for (rdn in x500name.rdNs) { + for (rdn in x500name.x500Name.rdNs) { val component = rdn.first.value.toString() if (exactMatch && component == query) { results += party @@ -200,4 +196,4 @@ class PersistentIdentityService(identities: Iterable = empt "Issuing certificate's public key must match the party key ${party.owningKey.toStringShort()}." } } -} \ No newline at end of file +} diff --git a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt index 00b293c539..fe21dac679 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt @@ -35,7 +35,7 @@ fun freshCertificate(identityService: IdentityService, val issuerCertificate = issuer.certificate val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, 3650.days, issuerCertificate) val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, - issuerSigner, issuer.name, subjectPublicKey, window) + issuerSigner, issuer.name.x500Name, subjectPublicKey, window) val certFactory = CertificateFactory.getInstance("X509") val ourCertPath = certFactory.generateCertPath(listOf(ourCertificate.cert) + issuer.certPath.certificates) val anonymisedIdentity = PartyAndCertificate(ourCertPath) diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt index 2e375d78f9..c214e23d51 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/ArtemisMessagingServer.kt @@ -5,8 +5,8 @@ import io.netty.handler.ssl.SslHandler import net.corda.core.concurrent.CordaFuture import net.corda.core.crypto.AddressFormatException import net.corda.core.crypto.newSecureRandom -import net.corda.core.utilities.parsePublicKeyBase58 import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.ThreadBox import net.corda.core.internal.concurrent.openFuture import net.corda.core.internal.div @@ -51,7 +51,6 @@ import org.apache.activemq.artemis.spi.core.security.jaas.CertificateCallback import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal import org.apache.activemq.artemis.utils.ConfigurationHelper -import org.bouncycastle.asn1.x500.X500Name import rx.Subscription import java.io.IOException import java.math.BigInteger @@ -373,7 +372,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, } } - private fun deployBridge(address: ArtemisPeerAddress, legalName: X500Name) { + private fun deployBridge(address: ArtemisPeerAddress, legalName: CordaX500Name) { deployBridge(address.queueName, address.hostAndPort, legalName) } @@ -386,7 +385,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: NetworkHostAndPort, legalName: X500Name) { + private fun deployBridge(queueName: String, target: NetworkHostAndPort, legalName: CordaX500Name) { val connectionDirection = ConnectionDirection.Outbound( connectorFactoryClassName = VerifyingNettyConnectorFactory::class.java.name, expectedCommonName = legalName @@ -425,7 +424,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, private fun getBridgeName(queueName: String, hostAndPort: NetworkHostAndPort): String = "$queueName -> $hostAndPort" // This is called on one of Artemis' background threads - internal fun hostVerificationFail(expectedLegalName: X500Name, errorMsg: String?) { + internal fun hostVerificationFail(expectedLegalName: CordaX500Name, errorMsg: String?) { log.error(errorMsg) 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! @@ -434,7 +433,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration, } // This is called on one of Artemis' background threads - internal fun onTcpConnection(peerLegalName: X500Name) { + internal fun onTcpConnection(peerLegalName: CordaX500Name) { if (peerLegalName == config.networkMapService?.legalName) { _networkMapConnectionFuture!!.set(Unit) } @@ -493,7 +492,7 @@ private class VerifyingNettyConnector(configuration: MutableMap, override fun createConnection(): Connection? { val connection = super.createConnection() as? NettyConnection if (sslEnabled && connection != null) { - val expectedLegalName = configuration[ArtemisTcpTransport.VERIFY_PEER_LEGAL_NAME] as X500Name + val expectedLegalName = configuration[ArtemisTcpTransport.VERIFY_PEER_LEGAL_NAME] as CordaX500Name try { val session = connection.channel .pipeline() @@ -501,14 +500,14 @@ private class VerifyingNettyConnector(configuration: MutableMap, .engine() .session // Checks the peer name is the one we are expecting. - val peerLegalName = session.peerPrincipal.name.let(::X500Name) + val peerLegalName = CordaX500Name.parse(session.peerPrincipal.name) require(peerLegalName == expectedLegalName) { "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!" } // Make sure certificate has the same name. val peerCertificate = session.peerCertificateChain[0].toX509CertHolder() - require(peerCertificate.subject == expectedLegalName) { + require(peerCertificate.subject == expectedLegalName.x500Name) { "Peer has wrong subject name in the certificate - expected $expectedLegalName but got ${peerCertificate.subject}. This is either a fatal " + "misconfiguration by the remote peer or an SSL man-in-the-middle attack!" } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/Messaging.kt b/node/src/main/kotlin/net/corda/node/services/messaging/Messaging.kt index 4471cb24b2..062919084e 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/Messaging.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/Messaging.kt @@ -2,6 +2,7 @@ package net.corda.node.services.messaging import com.google.common.util.concurrent.ListenableFuture import net.corda.core.concurrent.CordaFuture +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.concurrent.openFuture import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.SingleMessageRecipient @@ -9,7 +10,6 @@ import net.corda.core.node.services.PartyInfo import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize -import org.bouncycastle.asn1.x500.X500Name import java.time.Instant import java.util.* import java.util.concurrent.atomic.AtomicBoolean @@ -225,7 +225,7 @@ interface Message { // or something like that. interface ReceivedMessage : Message { /** The authenticated sender. */ - val peer: X500Name + val peer: CordaX500Name /** Platform version of the sender's node. */ val platformVersion: Int } diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt index 4d4bbd65b4..545ba0233a 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/NodeMessagingClient.kt @@ -2,9 +2,10 @@ package net.corda.node.services.messaging import net.corda.core.concurrent.CordaFuture import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name +import net.corda.core.internal.ThreadBox import net.corda.core.internal.concurrent.andForget import net.corda.core.internal.concurrent.thenMatch -import net.corda.core.internal.ThreadBox import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.MessageRecipients import net.corda.core.messaging.RPCOps @@ -38,13 +39,15 @@ import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.client.* import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl -import org.bouncycastle.asn1.x500.X500Name import java.security.PublicKey import java.time.Instant import java.util.* import java.util.concurrent.* import javax.annotation.concurrent.ThreadSafe -import javax.persistence.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.Id +import javax.persistence.Lob // TODO: Stop the wallet explorer and other clients from using this class and get rid of persistentInbox @@ -245,7 +248,7 @@ class NodeMessagingClient(override val config: NodeConfiguration, }, {}) val myLegalName = loadKeyStore(config.sslKeystore, config.keyStorePassword).getX509Certificate(X509Utilities.CORDA_CLIENT_TLS).subject - rpcServer = RPCServer(rpcOps, NODE_USER, NODE_USER, locator, userService, myLegalName) + rpcServer = RPCServer(rpcOps, NODE_USER, NODE_USER, locator, userService, CordaX500Name.build(myLegalName)) fun checkVerifierCount() { if (session.queueQuery(SimpleString(VERIFICATION_REQUESTS_QUEUE_NAME)).consumerCount == 0) { @@ -377,7 +380,7 @@ class NodeMessagingClient(override val config: NodeConfiguration, val uuid = message.required(HDR_DUPLICATE_DETECTION_ID) { UUID.fromString(message.getStringProperty(it)) } log.trace { "Received message from: ${message.address} user: $user topic: $topic sessionID: $sessionID uuid: $uuid" } - return ArtemisReceivedMessage(TopicSession(topic, sessionID), X500Name(user), platformVersion, uuid, message) + return ArtemisReceivedMessage(TopicSession(topic, sessionID), CordaX500Name.parse(user), platformVersion, uuid, message) } catch (e: Exception) { log.error("Unable to process message, ignoring it: $message", e) return null @@ -390,7 +393,7 @@ class NodeMessagingClient(override val config: NodeConfiguration, } private class ArtemisReceivedMessage(override val topicSession: TopicSession, - override val peer: X500Name, + override val peer: CordaX500Name, override val platformVersion: Int, override val uniqueMessageId: UUID, private val message: ClientMessage) : ReceivedMessage { diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt index c04842e494..10b4373716 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt @@ -12,13 +12,16 @@ import com.google.common.collect.Multimaps import com.google.common.collect.SetMultimap import com.google.common.util.concurrent.ThreadFactoryBuilder import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.LazyStickyPool import net.corda.core.internal.LifeCycle import net.corda.core.messaging.RPCOps -import net.corda.core.utilities.seconds import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationDefaults.RPC_SERVER_CONTEXT -import net.corda.core.utilities.* +import net.corda.core.utilities.Try +import net.corda.core.utilities.debug +import net.corda.core.utilities.loggerFor +import net.corda.core.utilities.seconds import net.corda.node.services.RPCUserService import net.corda.nodeapi.* import net.corda.nodeapi.ArtemisMessagingComponent.Companion.NODE_USER @@ -32,7 +35,6 @@ import org.apache.activemq.artemis.api.core.client.ServerLocator import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl import org.apache.activemq.artemis.api.core.management.CoreNotificationType import org.apache.activemq.artemis.api.core.management.ManagementHelper -import org.bouncycastle.asn1.x500.X500Name import rx.Notification import rx.Observable import rx.Subscriber @@ -76,7 +78,7 @@ class RPCServer( private val rpcServerPassword: String, private val serverLocator: ServerLocator, private val userService: RPCUserService, - private val nodeLegalName: X500Name, + private val nodeLegalName: CordaX500Name, private val rpcConfiguration: RPCServerConfiguration = RPCServerConfiguration.default ) { private companion object { @@ -341,7 +343,7 @@ class RPCServer( val rpcUser = userService.getUser(validatedUser) if (rpcUser != null) { return rpcUser - } else if (X500Name(validatedUser) == nodeLegalName) { + } else if (CordaX500Name.parse(validatedUser) == nodeLegalName) { return nodeUser } else { throw IllegalArgumentException("Validated user '$validatedUser' is not an RPC user nor the NODE user") diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt index fa57922e1e..7b6a2b5346 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt @@ -2,6 +2,7 @@ package net.corda.node.services.network import net.corda.core.concurrent.CordaFuture import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.VisibleForTesting import net.corda.core.internal.bufferUntilSubscribed @@ -32,7 +33,6 @@ import net.corda.node.utilities.AddOrRemove import net.corda.node.utilities.DatabaseTransactionManager import net.corda.node.utilities.bufferUntilDatabaseCommit import net.corda.node.utilities.wrapWithDatabaseTransaction -import org.bouncycastle.asn1.x500.X500Name import org.hibernate.Session import rx.Observable import rx.subjects.PublishSubject @@ -90,7 +90,7 @@ open class PersistentNetworkMapCache(private val serviceHub: ServiceHubInternal) } // TODO See comment to queryByLegalName why it's left like that. - override fun getNodeByLegalName(principal: X500Name): NodeInfo? = partyNodes.singleOrNull { it.legalIdentity.name == principal } + override fun getNodeByLegalName(principal: CordaX500Name): NodeInfo? = partyNodes.singleOrNull { it.legalIdentity.name == principal } //serviceHub!!.database.transaction { queryByLegalName(principal).firstOrNull() } override fun getNodeByLegalIdentityKey(identityKey: PublicKey): NodeInfo? = serviceHub.database.transaction { queryByIdentityKey(identityKey).firstOrNull() } @@ -288,10 +288,7 @@ open class PersistentNetworkMapCache(private val serviceHub: ServiceHubInternal) } } - // TODO It's useless for now, because toString on X500 names is inconsistent and we have: - // C=ES,L=Madrid,O=Alice Corp,CN=Alice Corp - // CN=Alice Corp,O=Alice Corp,L=Madrid,C=ES - private fun queryByLegalName(name: X500Name): List { + private fun queryByLegalName(name: CordaX500Name): List { createSession { val query = it.createQuery( "SELECT n FROM ${NodeInfoSchemaV1.PersistentNodeInfo::class.java.name} n JOIN n.legalIdentitiesAndCerts l WHERE l.name = :name", diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyToX500NameAsStringConverter.kt b/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyToX500NameAsStringConverter.kt index 14942ce2ec..f93048868e 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyToX500NameAsStringConverter.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/AbstractPartyToX500NameAsStringConverter.kt @@ -1,15 +1,15 @@ package net.corda.node.services.persistence import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.IdentityService import net.corda.core.utilities.loggerFor -import org.bouncycastle.asn1.x500.X500Name import javax.persistence.AttributeConverter import javax.persistence.Converter /** - * Converter to persist a party as its's well known identity (where resolvable) - * Completely anonymous parties are stored as null (to preserve privacy) + * Converter to persist a party as its' well known identity (where resolvable). + * Completely anonymous parties are stored as null (to preserve privacy). */ @Converter(autoApply = true) class AbstractPartyToX500NameAsStringConverter(identitySvc: () -> IdentityService) : AttributeConverter { @@ -30,7 +30,7 @@ class AbstractPartyToX500NameAsStringConverter(identitySvc: () -> IdentityServic override fun convertToEntityAttribute(dbData: String?): AbstractParty? { if (dbData != null) { - val party = identityService.partyFromX500Name(X500Name(dbData)) + val party = identityService.partyFromX500Name(CordaX500Name.parse(dbData)) if (party != null) return party log.warn ("Identity service unable to resolve X500name: $dbData") } diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt index 70c7cde877..780d389ef8 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt @@ -3,9 +3,11 @@ package net.corda.node.services.transactions import co.paralleluniverse.fibers.Suspendable import com.google.common.util.concurrent.SettableFuture import net.corda.core.contracts.StateRef -import net.corda.core.crypto.* +import net.corda.core.crypto.DigitalSignature +import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.flows.NotaryException +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.services.NotaryService import net.corda.core.node.services.TimeWindowChecker @@ -18,7 +20,6 @@ import net.corda.core.utilities.* import net.corda.node.services.api.ServiceHubInternal import net.corda.node.utilities.AppendOnlyPersistentMap import net.corda.node.utilities.NODE_DATABASE_PREFIX -import org.bouncycastle.asn1.x500.X500Name import javax.persistence.Entity import kotlin.concurrent.thread @@ -106,7 +107,7 @@ class BFTNonValidatingNotaryService(override val services: ServiceHubInternal, c id = SecureHash.parse(it.consumingTxHash), inputIndex = it.consumingIndex, requestingParty = Party( - name = X500Name(it.party.name), + name = CordaX500Name.parse(it.party.name), owningKey = parsePublicKeyBase58(it.party.owningKey)))) }, toPersistentEntity = { (txHash, index) : StateRef, (id, inputIndex, requestingParty): UniquenessProvider.ConsumingTx -> diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt index 507b3d65e2..b17b9902fc 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt @@ -2,8 +2,7 @@ package net.corda.node.services.transactions import net.corda.core.contracts.StateRef import net.corda.core.crypto.SecureHash -import net.corda.core.utilities.parsePublicKeyBase58 -import net.corda.core.utilities.toBase58String +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.ThreadBox import net.corda.core.node.services.UniquenessException @@ -11,8 +10,10 @@ import net.corda.core.node.services.UniquenessProvider import net.corda.core.schemas.PersistentStateRef import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.loggerFor -import net.corda.node.utilities.* -import org.bouncycastle.asn1.x500.X500Name +import net.corda.core.utilities.parsePublicKeyBase58 +import net.corda.core.utilities.toBase58String +import net.corda.node.utilities.AppendOnlyPersistentMap +import net.corda.node.utilities.NODE_DATABASE_PREFIX import java.io.Serializable import java.util.* import javax.annotation.concurrent.ThreadSafe @@ -73,7 +74,7 @@ class PersistentUniquenessProvider : UniquenessProvider, SingletonSerializeAsTok id = SecureHash.parse(it.consumingTxHash), inputIndex = it.consumingIndex, requestingParty = Party( - name = X500Name(it.party.name), + name = CordaX500Name.parse(it.party.name), owningKey = parsePublicKeyBase58(it.party.owningKey)))) }, toPersistentEntity = { (txHash, index) : StateRef, (id, inputIndex, requestingParty) : UniquenessProvider.ConsumingTx -> diff --git a/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt b/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt index 765bbae85a..f8e3665dcd 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/KeyStoreUtilities.kt @@ -1,12 +1,12 @@ package net.corda.node.utilities import net.corda.core.crypto.Crypto +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.exists import net.corda.core.internal.read import net.corda.core.internal.toX509CertHolder import net.corda.core.internal.write import net.corda.core.utilities.cert -import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.cert.X509CertificateHolder import java.io.IOException import java.io.InputStream @@ -174,26 +174,26 @@ fun KeyStore.getSupportedKey(alias: String, keyPassword: String): PrivateKey { class KeyStoreWrapper(private val storePath: Path, private val storePassword: String) { private val keyStore = storePath.read { loadKeyStore(it, storePassword) } - private fun createCertificate(serviceName: X500Name, pubKey: PublicKey): CertPath { + private fun createCertificate(serviceName: CordaX500Name, pubKey: PublicKey): CertPath { val clientCertPath = keyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA) // Assume key password = store password. val clientCA = certificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA) // Create new keys and store in keystore. - val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName, pubKey) + val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, clientCA.certificate, clientCA.keyPair, serviceName.x500Name, pubKey) val certPath = CertificateFactory.getInstance("X509").generateCertPath(listOf(cert.cert) + clientCertPath) require(certPath.certificates.isNotEmpty()) { "Certificate path cannot be empty" } // TODO: X509Utilities.validateCertificateChain() return certPath } - fun signAndSaveNewKeyPair(serviceName: X500Name, privateKeyAlias: String, keyPair: KeyPair) { + fun signAndSaveNewKeyPair(serviceName: CordaX500Name, privateKeyAlias: String, keyPair: KeyPair) { val certPath = createCertificate(serviceName, keyPair.public) // Assume key password = store password. keyStore.addOrReplaceKey(privateKeyAlias, keyPair.private, storePassword.toCharArray(), certPath.certificates.toTypedArray()) keyStore.save(storePath, storePassword) } - fun savePublicKey(serviceName: X500Name, pubKeyAlias: String, pubKey: PublicKey) { + fun savePublicKey(serviceName: CordaX500Name, pubKeyAlias: String, pubKey: PublicKey) { val certPath = createCertificate(serviceName, pubKey) // Assume key password = store password. keyStore.addOrReplaceCertificate(pubKeyAlias, certPath.certificates.first()) diff --git a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt index 81d10b45b6..70ba6af802 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/ServiceIdentityGenerator.kt @@ -2,10 +2,10 @@ package net.corda.node.utilities import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.generateKeyPair +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party 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 @@ -25,7 +25,7 @@ object ServiceIdentityGenerator { // TODO: This needs to write out to the key store, not just files on disk fun generateToDisk(dirs: List, serviceId: String, - serviceName: X500Name, + serviceName: CordaX500Name, threshold: Int = 1): Party { log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" } val keyPairs = (1..dirs.size).map { generateKeyPair() } diff --git a/node/src/main/kotlin/net/corda/node/utilities/X509Utilities.kt b/node/src/main/kotlin/net/corda/node/utilities/X509Utilities.kt index af3b4bc1eb..ab042fb709 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/X509Utilities.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/X509Utilities.kt @@ -3,6 +3,7 @@ package net.corda.node.utilities import net.corda.core.crypto.Crypto import net.corda.core.crypto.SignatureScheme import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.cert import net.corda.core.utilities.days import net.corda.core.utilities.millis @@ -106,7 +107,29 @@ object X509Utilities { @JvmStatic fun createCertificate(certificateType: CertificateType, issuerCertificate: X509CertificateHolder, issuerKeyPair: KeyPair, - subject: X500Name, subjectPublicKey: PublicKey, + subject: CordaX500Name, subjectPublicKey: PublicKey, + validityWindow: Pair = DEFAULT_VALIDITY_WINDOW, + nameConstraints: NameConstraints? = null): X509CertificateHolder { + val window = getCertificateValidityWindow(validityWindow.first, validityWindow.second, issuerCertificate) + return createCertificate(certificateType, issuerCertificate.subject, issuerKeyPair, subject.x500Name, subjectPublicKey, window, nameConstraints) + } + + /** + * Create a X509 v3 cert. + * @param issuerCertificate The Public certificate of the root CA above this used to sign it. + * @param issuerKeyPair The KeyPair of the root CA above this used to sign it. + * @param subject subject of the generated certificate. + * @param subjectPublicKey subject 's public key. + * @param validityWindow The certificate's validity window. Default to [DEFAULT_VALIDITY_WINDOW] if not provided. + * @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. + */ + @JvmStatic + fun createCertificate(certificateType: CertificateType, + issuerCertificate: X509CertificateHolder, + issuerKeyPair: KeyPair, + subject: X500Name, + subjectPublicKey: PublicKey, validityWindow: Pair = DEFAULT_VALIDITY_WINDOW, nameConstraints: NameConstraints? = null): X509CertificateHolder { val window = getCertificateValidityWindow(validityWindow.first, validityWindow.second, issuerCertificate) diff --git a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt index bcd1c17674..b3e3377956 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/registration/NetworkRegistrationHelper.kt @@ -4,7 +4,6 @@ import net.corda.core.crypto.Crypto import net.corda.core.utilities.cert import net.corda.core.internal.* import net.corda.core.utilities.seconds -import net.corda.core.utilities.validateX500Name import net.corda.node.services.config.NodeConfiguration import net.corda.node.utilities.* import net.corda.node.utilities.X509Utilities.CORDA_CLIENT_CA @@ -45,7 +44,6 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v */ // TODO: Stop killing the calling process from within a called function. fun buildKeystore() { - validateX500Name(config.myLegalName) config.certificatesDirectory.createDirectories() val caKeyStore = loadOrCreateKeyStore(config.nodeKeystore, keystorePassword) if (!caKeyStore.containsAlias(CORDA_CLIENT_CA)) { @@ -53,7 +51,7 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v // We use the self sign certificate to store the key temporarily in the keystore while waiting for the request approval. if (!caKeyStore.containsAlias(SELF_SIGNED_PRIVATE_KEY)) { val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) - val selfSignCert = X509Utilities.createSelfSignedCACertificate(config.myLegalName, keyPair) + val selfSignCert = X509Utilities.createSelfSignedCACertificate(config.myLegalName.x500Name, keyPair) // Save to the key store. caKeyStore.addOrReplaceKey(SELF_SIGNED_PRIVATE_KEY, keyPair.private, privateKeyPassword.toCharArray(), arrayOf(selfSignCert)) @@ -126,7 +124,7 @@ class NetworkRegistrationHelper(private val config: NodeConfiguration, private v private fun submitOrResumeCertificateSigningRequest(keyPair: KeyPair): String { // Retrieve request id from file if exists, else post a request to server. return if (!requestIdStore.exists()) { - val request = X509Utilities.createCertificateSigningRequest(config.myLegalName, config.emailAddress, keyPair) + val request = X509Utilities.createCertificateSigningRequest(config.myLegalName.x500Name, config.emailAddress, keyPair) val writer = StringWriter() JcaPEMWriter(writer).use { it.writeObject(PemObject("CERTIFICATE REQUEST", request.encoded)) diff --git a/node/src/smoke-test/kotlin/net/corda/node/CordappSmokeTest.kt b/node/src/smoke-test/kotlin/net/corda/node/CordappSmokeTest.kt index f295c81398..f6dd8060af 100644 --- a/node/src/smoke-test/kotlin/net/corda/node/CordappSmokeTest.kt +++ b/node/src/smoke-test/kotlin/net/corda/node/CordappSmokeTest.kt @@ -2,6 +2,7 @@ package net.corda.node import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.* +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.copyToDirectory import net.corda.core.internal.createDirectories @@ -9,7 +10,6 @@ import net.corda.core.internal.div import net.corda.core.internal.list import net.corda.core.messaging.startFlow import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.getX500Name import net.corda.core.utilities.unwrap import net.corda.nodeapi.User import net.corda.smoketesting.NodeConfig @@ -29,7 +29,7 @@ class CordappSmokeTest { private val factory = NodeProcess.Factory() private val aliceConfig = NodeConfig( - legalName = getX500Name(O = "Alice Corp", L = "Madrid", C = "ES"), + legalName = CordaX500Name(organisation = "Alice Corp", locality = "Madrid", country = "ES"), p2pPort = port.andIncrement, rpcPort = port.andIncrement, webPort = port.andIncrement, diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index d22f18a2aa..794c1793c9 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -10,6 +10,7 @@ import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.FlowStateMachine import net.corda.core.internal.concurrent.map @@ -46,7 +47,6 @@ import net.corda.testing.contracts.fillWithSomeTestCash import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.MockNetwork import org.assertj.core.api.Assertions.assertThat -import org.bouncycastle.asn1.x500.X500Name import org.junit.After import org.junit.Before import org.junit.Test @@ -307,7 +307,7 @@ class TwoPartyTradeFlowTests { // of gets and puts. private fun makeNodeWithTracking( networkMapAddress: SingleMessageRecipient?, - name: X500Name): MockNetwork.MockNode { + name: CordaX500Name): MockNetwork.MockNode { // Create a node in the mock network ... return mockNet.createNode(networkMapAddress, nodeFactory = object : MockNetwork.Factory { override fun create(config: NodeConfiguration, diff --git a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt index 75ec51150a..f1710701d0 100644 --- a/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/NotaryChangeTests.kt @@ -4,12 +4,12 @@ import net.corda.core.contracts.* import net.corda.core.crypto.generateKeyPair import net.corda.core.flows.NotaryChangeFlow import net.corda.core.flows.StateReplacementException +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.services.ServiceInfo import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.getX500Name import net.corda.core.utilities.seconds import net.corda.node.internal.AbstractNode import net.corda.node.services.network.NetworkMapService @@ -21,7 +21,6 @@ import net.corda.testing.dummyCommand import net.corda.testing.getTestPartyAndCertificate import net.corda.testing.node.MockNetwork import org.assertj.core.api.Assertions.assertThatExceptionOfType -import org.bouncycastle.asn1.x500.X500Name import org.junit.After import org.junit.Before import org.junit.Test @@ -88,7 +87,7 @@ class NotaryChangeTests { @Test fun `should throw when a participant refuses to change Notary`() { val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode) - val newEvilNotary = getTestPartyAndCertificate(getX500Name(OU="Evil Notary",O="Evil R3",L="London",C="GB"), generateKeyPair().public) + val newEvilNotary = getTestPartyAndCertificate(CordaX500Name(organisation = "Evil R3", locality = "London", country = "GB"), generateKeyPair().public) val flow = NotaryChangeFlow(state, newEvilNotary.party) val future = clientNodeA.services.startFlow(flow) diff --git a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt index afe591c168..783922c4dd 100644 --- a/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/events/NodeSchedulerServiceTest.kt @@ -6,13 +6,13 @@ import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogicRef import net.corda.core.flows.FlowLogicRefFactory import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.ServiceHub import net.corda.core.node.services.VaultService import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.days -import net.corda.core.utilities.getX500Name import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.persistence.DBCheckpointStorage import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl @@ -31,7 +31,6 @@ import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties import net.corda.testing.node.MockServices.Companion.makeTestIdentityService import net.corda.testing.node.TestClock import org.assertj.core.api.Assertions.assertThat -import org.bouncycastle.asn1.x500.X500Name import org.junit.After import org.junit.Before import org.junit.Test @@ -82,7 +81,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { val kms = MockKeyManagementService(identityService, ALICE_KEY) database.transaction { - val nullIdentity = X500Name("cn=None") + val nullIdentity = CordaX500Name(organisation = "None", locality = "None", country = "GB") val mockMessagingService = InMemoryMessagingNetwork(false).InMemoryMessaging( false, InMemoryMessagingNetwork.PeerHandle(0, nullIdentity), @@ -90,7 +89,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() { database) services = object : MockServiceHubInternal( database, - testNodeConfiguration(Paths.get("."), getX500Name(O = "Alice", L = "London", C = "GB")), + testNodeConfiguration(Paths.get("."), CordaX500Name(organisation = "Alice", locality = "London", country = "GB")), overrideClock = testClock, keyManagement = kms, network = mockMessagingService), TestReference { diff --git a/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt index 30c0de2843..ab80752849 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/AbstractNetworkMapServiceTest.kt @@ -1,12 +1,12 @@ package net.corda.node.services.network import net.corda.core.concurrent.CordaFuture +import net.corda.core.identity.CordaX500Name import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.NodeInfo import net.corda.core.node.services.ServiceInfo import net.corda.core.serialization.deserialize import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.getX500Name import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.messaging.MessagingService import net.corda.node.services.messaging.send @@ -31,7 +31,6 @@ import net.corda.testing.DUMMY_MAP 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.junit.After import org.junit.Before import org.junit.Test @@ -47,7 +46,7 @@ abstract class AbstractNetworkMapServiceTest lateinit var alice: MockNode companion object { - val subscriberLegalName = getX500Name(O="Subscriber",L="New York",C="US") + val subscriberLegalName = CordaX500Name(organisation ="Subscriber", locality ="New York", country ="US") } @Before @@ -251,14 +250,14 @@ abstract class AbstractNetworkMapServiceTest mockNet.runNetwork() } - private fun addNewNodeToNetworkMap(legalName: X500Name): MockNode { + private fun addNewNodeToNetworkMap(legalName: CordaX500Name): MockNode { val node = mockNet.createNode(mapServiceNode.network.myAddress, legalName = legalName) mockNet.runNetwork() lastSerial = System.currentTimeMillis() return node } - private fun newNodeSeparateFromNetworkMap(legalName: X500Name): MockNode { + private fun newNodeSeparateFromNetworkMap(legalName: CordaX500Name): MockNode { return mockNet.createNode(legalName = legalName, nodeFactory = NoNMSNodeFactory) } diff --git a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt index bbf0c8ca50..5df89b7c32 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/InMemoryIdentityServiceTests.kt @@ -3,17 +3,16 @@ package net.corda.node.services.network import net.corda.core.crypto.Crypto import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.UnknownAnonymousPartyException import net.corda.node.utilities.CertificateAndKeyPair import net.corda.core.utilities.cert -import net.corda.core.utilities.getX500Name import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.utilities.CertificateType import net.corda.node.utilities.X509Utilities import net.corda.testing.* -import org.bouncycastle.asn1.x500.X500Name import org.junit.Test import java.security.cert.CertificateFactory import kotlin.test.assertEquals @@ -63,7 +62,7 @@ class InMemoryIdentityServiceTests { val service = InMemoryIdentityService(trustRoot = trustRoot.certificate) service.verifyAndRegisterIdentity(ALICE_IDENTITY) service.verifyAndRegisterIdentity(BOB_IDENTITY) - val alicente = getTestPartyAndCertificate(getX500Name(O = "Alicente Worldwide", L = "London", C = "GB"), generateKeyPair().public) + val alicente = getTestPartyAndCertificate(CordaX500Name(organisation = "Alicente Worldwide", locality = "London", country = "GB"), generateKeyPair().public) service.verifyAndRegisterIdentity(alicente) assertEquals(setOf(ALICE, alicente.party), service.partiesFromName("Alice", false)) assertEquals(setOf(ALICE), service.partiesFromName("Alice Corp", true)) @@ -73,8 +72,8 @@ class InMemoryIdentityServiceTests { @Test fun `get identity by name`() { val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) - val identities = listOf("Node A", "Node B", "Node C") - .map { getTestPartyAndCertificate(getX500Name(O = it, OU = "corda", L = "London", C = "GB"), generateKeyPair().public) } + val identities = listOf("Org A", "Org B", "Org C") + .map { getTestPartyAndCertificate(CordaX500Name(organisation = it, locality = "London", country = "GB"), generateKeyPair().public) } assertNull(service.partyFromX500Name(identities.first().name)) identities.forEach { service.verifyAndRegisterIdentity(it) } identities.forEach { assertEquals(it.party, service.partyFromX500Name(it.name)) } @@ -87,7 +86,7 @@ class InMemoryIdentityServiceTests { fun `assert unknown anonymous key is unrecognised`() { withTestSerialization { val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) - val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey) + val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name.x500Name, rootKey) val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) // TODO: Generate certificate with an EdDSA key rather than ECDSA @@ -152,17 +151,18 @@ class InMemoryIdentityServiceTests { assertFailsWith { val owningKey = Crypto.decodePublicKey(trustRoot.certificate.subjectPublicKeyInfo.encoded) - service.assertOwnership(Party(trustRoot.certificate.subject, owningKey), anonymousAlice.party.anonymise()) + val subject = CordaX500Name.build(trustRoot.certificate.subject) + service.assertOwnership(Party(subject, owningKey), anonymousAlice.party.anonymise()) } } } - private fun createParty(x500Name: X500Name, ca: CertificateAndKeyPair): Pair { + private fun createParty(x500Name: CordaX500Name, ca: CertificateAndKeyPair): Pair { val certFactory = CertificateFactory.getInstance("X509") val issuerKeyPair = generateKeyPair() val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca) val txKey = Crypto.generateKeyPair() - val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name, txKey.public) + val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name.x500Name, txKey.public) val txCertPath = certFactory.generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates) return Pair(issuer, PartyAndCertificate(txCertPath)) } diff --git a/node/src/test/kotlin/net/corda/node/services/network/PersistentIdentityServiceTests.kt b/node/src/test/kotlin/net/corda/node/services/network/PersistentIdentityServiceTests.kt index a87c0bf629..fd47618272 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/PersistentIdentityServiceTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/PersistentIdentityServiceTests.kt @@ -3,20 +3,19 @@ package net.corda.node.services.network import net.corda.core.crypto.Crypto import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService import net.corda.core.node.services.UnknownAnonymousPartyException import net.corda.node.utilities.CertificateAndKeyPair import net.corda.core.utilities.cert -import net.corda.core.utilities.getX500Name import net.corda.node.services.identity.PersistentIdentityService import net.corda.node.utilities.CertificateType import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.X509Utilities import net.corda.testing.* import net.corda.testing.node.MockServices -import org.bouncycastle.asn1.x500.X500Name import org.junit.After import org.junit.Before import org.junit.Test @@ -97,7 +96,7 @@ class PersistentIdentityServiceTests { identityService.verifyAndRegisterIdentity(ALICE_IDENTITY) identityService.verifyAndRegisterIdentity(BOB_IDENTITY) } - val alicente = getTestPartyAndCertificate(getX500Name(O = "Alicente Worldwide", L = "London", C = "GB"), generateKeyPair().public) + val alicente = getTestPartyAndCertificate(CordaX500Name(organisation = "Alicente Worldwide", locality = "London", country = "GB"), generateKeyPair().public) database.transaction { identityService.verifyAndRegisterIdentity(alicente) assertEquals(setOf(ALICE, alicente.party), identityService.partiesFromName("Alice", false)) @@ -108,8 +107,8 @@ class PersistentIdentityServiceTests { @Test fun `get identity by name`() { - val identities = listOf("Node A", "Node B", "Node C") - .map { getTestPartyAndCertificate(getX500Name(O = it, OU = "corda", L = "London", C = "GB"), generateKeyPair().public) } + val identities = listOf("Organisation A", "Organisation B", "Organisation C") + .map { getTestPartyAndCertificate(CordaX500Name(organisation = it, locality = "London", country = "GB"), generateKeyPair().public) } database.transaction { assertNull(identityService.partyFromX500Name(identities.first().name)) } @@ -132,7 +131,7 @@ class PersistentIdentityServiceTests { fun `assert unknown anonymous key is unrecognised`() { withTestSerialization { val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) - val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey) + val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name.x500Name, rootKey) val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_IDENTITY_SIGNATURE_SCHEME) val identity = Party(rootCert) val txIdentity = AnonymousParty(txKey.public) @@ -214,7 +213,8 @@ class PersistentIdentityServiceTests { assertFailsWith { val owningKey = Crypto.decodePublicKey(trustRoot.certificate.subjectPublicKeyInfo.encoded) database.transaction { - identityService.assertOwnership(Party(trustRoot.certificate.subject, owningKey), anonymousAlice.party.anonymise()) + val subject = CordaX500Name.build(trustRoot.certificate.subject) + identityService.assertOwnership(Party(subject, owningKey), anonymousAlice.party.anonymise()) } } } @@ -256,12 +256,12 @@ class PersistentIdentityServiceTests { assertEquals(anonymousBob, bobReload!!) } - private fun createParty(x500Name: X500Name, ca: CertificateAndKeyPair): Pair { + private fun createParty(x500Name: CordaX500Name, ca: CertificateAndKeyPair): Pair { val certFactory = CertificateFactory.getInstance("X509") val issuerKeyPair = generateKeyPair() val issuer = getTestPartyAndCertificate(x500Name, issuerKeyPair.public, ca) val txKey = Crypto.generateKeyPair() - val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name, txKey.public) + val txCert = X509Utilities.createCertificate(CertificateType.IDENTITY, issuer.certificate, issuerKeyPair, x500Name.x500Name, txKey.public) val txCertPath = certFactory.generateCertPath(listOf(txCert.cert) + issuer.certPath.certificates) return Pair(issuer, PartyAndCertificate(txCertPath)) } diff --git a/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt b/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt index 06d4f37a54..48b0c57b4d 100644 --- a/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/network/PersistentNetworkMapCacheTest.kt @@ -4,13 +4,10 @@ import co.paralleluniverse.fibers.Suspendable import net.corda.core.flows.FlowLogic import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatingFlow +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.NodeInfo -import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.seconds -import net.corda.core.utilities.toBase58String -import net.corda.core.utilities.unwrap +import net.corda.core.utilities.* import net.corda.node.internal.Node import net.corda.testing.ALICE import net.corda.testing.BOB @@ -18,7 +15,6 @@ import net.corda.testing.CHARLIE import net.corda.testing.DUMMY_NOTARY import net.corda.testing.node.NodeBasedTest import org.assertj.core.api.Assertions.assertThat -import org.bouncycastle.asn1.x500.X500Name import org.junit.Before import org.junit.Test import kotlin.test.assertEquals @@ -26,7 +22,7 @@ import kotlin.test.assertFails class PersistentNetworkMapCacheTest : NodeBasedTest() { val partiesList = listOf(DUMMY_NOTARY, ALICE, BOB) - val addressesMap: HashMap = HashMap() + val addressesMap: HashMap = HashMap() val infos: MutableSet = HashSet() @Before diff --git a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt index dda7feed32..a3c365a801 100644 --- a/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/statemachine/FlowFrameworkTests.kt @@ -9,6 +9,7 @@ import net.corda.core.contracts.StateAndRef import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.random63BitValue import net.corda.core.flows.* +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.concurrent.flatMap import net.corda.core.internal.concurrent.map @@ -21,8 +22,11 @@ import net.corda.core.serialization.serialize import net.corda.core.toFuture import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.TransactionBuilder -import net.corda.core.utilities.* +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker.Change +import net.corda.core.utilities.getOrThrow +import net.corda.core.utilities.unwrap import net.corda.finance.DOLLARS import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashPaymentFlow @@ -77,7 +81,7 @@ class FlowFrameworkTests { // We intentionally create our own notary and ignore the one provided by the network val notaryKeyPair = generateKeyPair() - val notaryService = ServiceInfo(ValidatingNotaryService.type, getX500Name(O = "notary-service-2000", L = "London", C = "GB")) + val notaryService = ServiceInfo(ValidatingNotaryService.type, CordaX500Name(organisation = "Notary service 2000", locality = "London", country = "GB")) 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. diff --git a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt index 16780717e0..feb297f9ef 100644 --- a/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt @@ -3,6 +3,7 @@ package net.corda.node.services.vault import net.corda.core.contracts.* import net.corda.core.crypto.SecureHash import net.corda.core.crypto.entropyToKeyPair +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.* @@ -54,7 +55,7 @@ class VaultQueryTests : TestDependencyInjectionBase() { // test cash notary val CASH_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(21)) } - val CASH_NOTARY: Party get() = Party(getX500Name(O = "Cash Notary Service", OU = "corda", L = "Zurich", C = "CH"), CASH_NOTARY_KEY.public) + val CASH_NOTARY: Party get() = Party(CordaX500Name(organisation = "Cash Notary Service", locality = "Zurich", country = "CH"), CASH_NOTARY_KEY.public) val CASH_NOTARY_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(CASH_NOTARY.nameOrNull(), CASH_NOTARY_KEY.public) @Before @@ -1484,15 +1485,15 @@ class VaultQueryTests : TestDependencyInjectionBase() { fun `unconsumed fungible assets for selected issuer parties`() { // GBP issuer val gbpCashIssuerKey = entropyToKeyPair(BigInteger.valueOf(1001)) - val gbpCashIssuer = Party(getX500Name(O = "British Pounds Cash Issuer", OU = "corda", L = "London", C = "GB"), gbpCashIssuerKey.public).ref(1) + val gbpCashIssuer = Party(CordaX500Name(organisation = "British Pounds Cash Issuer", locality = "London", country = "GB"), gbpCashIssuerKey.public).ref(1) val gbpCashIssuerServices = MockServices(gbpCashIssuerKey) // USD issuer val usdCashIssuerKey = entropyToKeyPair(BigInteger.valueOf(1002)) - val usdCashIssuer = Party(getX500Name(O = "US Dollars Cash Issuer", OU = "corda", L = "New York", C = "US"), usdCashIssuerKey.public).ref(1) + val usdCashIssuer = Party(CordaX500Name(organisation = "US Dollars Cash Issuer", locality = "New York", country = "US"), usdCashIssuerKey.public).ref(1) val usdCashIssuerServices = MockServices(usdCashIssuerKey) // CHF issuer val chfCashIssuerKey = entropyToKeyPair(BigInteger.valueOf(1003)) - val chfCashIssuer = Party(getX500Name(O = "Swiss Francs Cash Issuer", OU = "corda", L = "Zurich", C = "CH"), chfCashIssuerKey.public).ref(1) + val chfCashIssuer = Party(CordaX500Name(organisation = "Swiss Francs Cash Issuer", locality = "Zurich", country = "CH"), chfCashIssuerKey.public).ref(1) val chfCashIssuerServices = MockServices(chfCashIssuerKey) database.transaction { diff --git a/node/src/test/kotlin/net/corda/node/utilities/X509UtilitiesTest.kt b/node/src/test/kotlin/net/corda/node/utilities/X509UtilitiesTest.kt index 930b8a8e78..e79ead0fa9 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/X509UtilitiesTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/X509UtilitiesTest.kt @@ -11,7 +11,6 @@ import net.corda.core.serialization.serialize import net.corda.core.utilities.cert import net.corda.core.utilities.commonName import net.corda.core.utilities.getX500Name -import net.corda.core.utilities.organisation import net.corda.node.serialization.KryoServerSerializationScheme import net.corda.node.services.config.createKeystoreForCordaNode import net.corda.nodeapi.internal.serialization.AllWhitelist @@ -318,7 +317,7 @@ class X509UtilitiesTest { val peerChain = clientSocket.session.peerCertificates val peerX500Principal = (peerChain[0] as X509Certificate).subjectX500Principal val x500name = X500Name(peerX500Principal.name) - assertEquals(MEGA_CORP.name, x500name) + assertEquals(MEGA_CORP.name.x500Name, x500name) X509Utilities.validateCertificateChain(trustStore.getX509Certificate(X509Utilities.CORDA_ROOT_CA), *peerChain) val output = DataOutputStream(clientSocket.outputStream) output.writeUTF("Hello World") @@ -409,7 +408,7 @@ class X509UtilitiesTest { emptyMap(), true, SerializationContext.UseCase.P2P) - val expected: X509CertificateHolder = X509Utilities.createSelfSignedCACertificate(ALICE.name, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) + val expected: X509CertificateHolder = X509Utilities.createSelfSignedCACertificate(ALICE.name.x500Name, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)) val serialized = expected.serialize(factory, context).bytes val actual: X509CertificateHolder = serialized.deserialize(factory, context) assertEquals(expected, actual) @@ -426,8 +425,8 @@ class X509UtilitiesTest { SerializationContext.UseCase.P2P) val certFactory = CertificateFactory.getInstance("X509") val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) - val rootCACert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootCAKey) - val certificate = X509Utilities.createCertificate(CertificateType.TLS, rootCACert, rootCAKey, BOB.name, BOB_PUBKEY) + val rootCACert = X509Utilities.createSelfSignedCACertificate(ALICE.name.x500Name, rootCAKey) + val certificate = X509Utilities.createCertificate(CertificateType.TLS, rootCACert, rootCAKey, BOB.name.x500Name, BOB_PUBKEY) val expected = certFactory.generateCertPath(listOf(certificate.cert, rootCACert.cert)) val serialized = expected.serialize(factory, context).bytes val actual: CertPath = serialized.deserialize(factory, context) diff --git a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt index 38e8dabf99..542a4e610e 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/registration/NetworkisRegistrationHelperTest.kt @@ -5,6 +5,7 @@ import com.nhaarman.mockito_kotlin.eq import com.nhaarman.mockito_kotlin.mock import net.corda.core.crypto.Crypto import net.corda.core.crypto.SecureHash +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.exists import net.corda.core.internal.toTypedArray import net.corda.core.internal.toX509CertHolder @@ -15,6 +16,7 @@ import net.corda.node.utilities.X509Utilities import net.corda.node.utilities.loadKeyStore import net.corda.testing.ALICE import net.corda.testing.testNodeConfiguration +import org.bouncycastle.asn1.x500.X500Name import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 7d1587af73..170f9e265c 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -37,9 +37,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.attachmentdemo.AttachmentDemoFlow"]]] directory "./build/nodes" - networkMap "O=Notary Service,OU=corda,L=Zurich,C=CH" + networkMap "O=Notary Service,L=Zurich,C=CH" node { - name "O=Notary Service,OU=corda,L=Zurich,C=CH" + name "O=Notary Service,L=Zurich,C=CH" advertisedServices["corda.notary.validating"] p2pPort 10002 rpcPort 10003 diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index 16bb935396..1c15f0147d 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -50,9 +50,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { directory "./build/nodes" // This name "Notary" is hard-coded into BankOfCordaClientApi so if you change it here, change it there too. // In this demo the node that runs a standalone notary also acts as the network map server. - networkMap "O=Notary Service,OU=corda,L=Zurich,C=CH" + networkMap "O=Notary Service,L=Zurich,C=CH" node { - name "O=Notary Service,OU=corda,L=Zurich,C=CH" + name "O=Notary Service,L=Zurich,C=CH" advertisedServices = ["corda.notary.validating"] p2pPort 10002 rpcPort 10003 diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt index c2819e94b8..8d94948992 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/BankOfCordaDriver.kt @@ -3,10 +3,10 @@ package net.corda.bank import joptsimple.OptionParser import net.corda.bank.api.BankOfCordaClientApi import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getX500Name import net.corda.finance.flows.CashExitFlow import net.corda.finance.flows.CashIssueAndPaymentFlow import net.corda.finance.flows.CashPaymentFlow @@ -28,7 +28,7 @@ fun main(args: Array) { val BANK_USERNAME = "bankUser" val BIGCORP_USERNAME = "bigCorpUser" -val BIGCORP_LEGAL_NAME = getX500Name(O = "BigCorporation", OU = "corda", L = "London", C = "GB") +val BIGCORP_LEGAL_NAME = CordaX500Name(organisation = "BigCorporation", locality = "London", country = "GB") private class BankOfCordaDriver { enum class Role { diff --git a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt index eb01a19ad3..e88c26868f 100644 --- a/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt +++ b/samples/bank-of-corda-demo/src/main/kotlin/net/corda/bank/api/BankOfCordaWebApi.kt @@ -1,13 +1,13 @@ package net.corda.bank.api import net.corda.core.contracts.Amount +import net.corda.core.identity.CordaX500Name import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.loggerFor import net.corda.finance.flows.CashIssueAndPaymentFlow -import org.bouncycastle.asn1.x500.X500Name import java.time.LocalDateTime import java.util.* import javax.ws.rs.* @@ -18,9 +18,9 @@ import javax.ws.rs.core.Response @Path("bank") class BankOfCordaWebApi(val rpc: CordaRPCOps) { data class IssueRequestParams(val amount: Long, val currency: String, - val issueToPartyName: X500Name, val issuerBankPartyRef: String, - val issuerBankName: X500Name, - val notaryName: X500Name) + val issueToPartyName: CordaX500Name, val issuerBankPartyRef: String, + val issuerBankName: CordaX500Name, + val notaryName: CordaX500Name) private companion object { val logger = loggerFor() diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index 1eef8f0ff1..d1bd45a246 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -50,9 +50,9 @@ dependencies { task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { directory "./build/nodes" - networkMap "O=Notary Service,OU=corda,L=Zurich,C=CH" + networkMap "O=Notary Service,L=Zurich,C=CH" node { - name "O=Notary Service,OU=corda,L=Zurich,C=CH" + name "O=Notary Service,L=Zurich,C=CH" advertisedServices = ["corda.notary.validating", "corda.interest_rates"] p2pPort 10002 rpcPort 10003 diff --git a/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt b/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt index f7ef2df219..3e6aa896a4 100644 --- a/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt +++ b/samples/irs-demo/src/test/kotlin/net/corda/irs/api/NodeInterestRatesTest.kt @@ -5,6 +5,7 @@ import net.corda.core.contracts.ContractState import net.corda.core.contracts.TransactionState import net.corda.core.crypto.MerkleTreeException import net.corda.core.crypto.generateKeyPair +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.services.ServiceInfo import net.corda.core.transactions.TransactionBuilder @@ -20,7 +21,6 @@ import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.configureDatabase import net.corda.testing.* import net.corda.testing.node.* -import org.bouncycastle.asn1.x500.X500Name import org.junit.After import org.junit.Assert import org.junit.Before @@ -45,7 +45,7 @@ class NodeInterestRatesTest : TestDependencyInjectionBase() { """.trimIndent()) val DUMMY_CASH_ISSUER_KEY = generateKeyPair() - val DUMMY_CASH_ISSUER = Party(getX500Name(O="Cash issuer",OU="corda",L="London",C="GB"), DUMMY_CASH_ISSUER_KEY.public) + val DUMMY_CASH_ISSUER = Party(CordaX500Name(organisation = "Cash issuer", locality = "London", country = "GB"), DUMMY_CASH_ISSUER_KEY.public) lateinit var oracle: NodeInterestRates.Oracle lateinit var database: CordaPersistence diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt index 638f8bb168..07ee598a81 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/VisualiserViewModel.kt @@ -7,13 +7,11 @@ import javafx.scene.layout.StackPane import javafx.scene.shape.Circle import javafx.scene.shape.Line import javafx.util.Duration +import net.corda.core.identity.CordaX500Name import net.corda.core.node.ScreenCoordinate import net.corda.core.utilities.ProgressTracker -import net.corda.core.utilities.getX500Name -import net.corda.core.utilities.organisation import net.corda.netmap.simulation.IRSSimulation import net.corda.testing.node.MockNetwork -import org.bouncycastle.asn1.x500.X500Name import java.util.* class VisualiserViewModel { @@ -128,7 +126,7 @@ class VisualiserViewModel { } } - fun makeNodeWidget(forNode: MockNetwork.MockNode, type: String, label: X500Name = getX500Name(O = "Bank of Bologna", OU = "Corda QA Department", L = "Bologna", C = "IT"), + fun makeNodeWidget(forNode: MockNetwork.MockNode, type: String, label: CordaX500Name = CordaX500Name(organisation = "Bank of Bologna", locality = "Bologna", country = "IT"), nodeType: NetworkMapVisualiser.NodeType, index: Int): NodeWidget { fun emitRadarPulse(initialRadius: Double, targetRadius: Double, duration: Double): Pair { val pulse = Circle(initialRadius).apply { diff --git a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt index 7998e98e6a..ab4cd92f88 100644 --- a/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt +++ b/samples/network-visualiser/src/main/kotlin/net/corda/netmap/simulation/Simulation.kt @@ -1,14 +1,13 @@ package net.corda.netmap.simulation import net.corda.core.flows.FlowLogic +import net.corda.core.identity.CordaX500Name import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.node.CityDatabase import net.corda.core.node.WorldMapLocation import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.utilities.ProgressTracker -import net.corda.core.utilities.getX500Name -import net.corda.core.utilities.locality import net.corda.irs.api.NodeInterestRates import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.network.NetworkMapService @@ -72,7 +71,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, val cfg = testNodeConfiguration( baseDirectory = config.baseDirectory, - myLegalName = getX500Name(O = "Bank $letter", L = city, C = country)) + myLegalName = CordaX500Name(organisation = "Bank $letter", locality = city, country = country)) return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, overrideServices, entropyRoot) } @@ -112,7 +111,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean, object RatesOracleFactory : MockNetwork.Factory { // TODO: Make a more realistic legal name - val RATES_SERVICE_NAME = getX500Name(O = "Rates Service Provider", OU = "corda", L = "Madrid", C = "ES") + val RATES_SERVICE_NAME = CordaX500Name(organisation = "Rates Service Provider", locality = "Madrid", country = "ES") override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?, advertisedServices: Set, id: Int, overrideServices: Map?, diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt index d5ffa5aa65..c13cb34c31 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/BFTNotaryCordform.kt @@ -3,12 +3,12 @@ package net.corda.notarydemo import net.corda.cordform.CordformContext import net.corda.cordform.CordformDefinition import net.corda.cordform.CordformNode +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.div import net.corda.core.internal.stream import net.corda.core.internal.toTypedArray import net.corda.core.node.services.ServiceInfo import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getX500Name import net.corda.demorun.runNodes import net.corda.demorun.util.* import net.corda.node.services.transactions.BFTNonValidatingNotaryService @@ -22,8 +22,8 @@ fun main(args: Array) = BFTNotaryCordform.runNodes() private val clusterSize = 4 // Minimum size that tolerates a faulty replica. private val notaryNames = createNotaryNames(clusterSize) -object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", notaryNames[0]) { - private val clusterName = getX500Name(O = "BFT", OU = "corda", L = "Zurich", C = "CH") +object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", notaryNames[0].x500Name) { + private val clusterName = CordaX500Name(organisation = "BFT", locality = "Zurich", country = "CH") private val advertisedService = ServiceInfo(BFTNonValidatingNotaryService.type, clusterName) init { @@ -65,6 +65,6 @@ object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", not } override fun setup(context: CordformContext) { - ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, advertisedService.type.id, clusterName, minCorrectReplicas(clusterSize)) + ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it.x500Name) }, advertisedService.type.id, clusterName, minCorrectReplicas(clusterSize)) } } diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt index dae26480dd..6d0b5f69c9 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/RaftNotaryCordform.kt @@ -3,10 +3,10 @@ package net.corda.notarydemo import net.corda.cordform.CordformContext import net.corda.cordform.CordformDefinition import net.corda.cordform.CordformNode +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.div import net.corda.core.node.services.ServiceInfo import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getX500Name import net.corda.demorun.runNodes import net.corda.demorun.util.* import net.corda.node.services.transactions.RaftValidatingNotaryService @@ -16,12 +16,12 @@ import net.corda.testing.BOB fun main(args: Array) = RaftNotaryCordform.runNodes() -internal fun createNotaryNames(clusterSize: Int) = (0 until clusterSize).map { getX500Name(O = "Notary Service $it", OU = "corda", L = "Zurich", C = "CH") } +internal fun createNotaryNames(clusterSize: Int) = (0 until clusterSize).map { CordaX500Name(commonName ="Notary Service $it", organisationUnit = "corda", organisation = "R3 Ltd", locality = "Zurich", state = null, country = "CH") } private val notaryNames = createNotaryNames(3) -object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", notaryNames[0]) { - private val clusterName = getX500Name(O = "Raft", OU = "corda", L = "Zurich", C = "CH") +object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", notaryNames[0].x500Name) { + private val clusterName = CordaX500Name(organisation = "Raft", locality = "Zurich", country = "CH") private val advertisedService = ServiceInfo(RaftValidatingNotaryService.type, clusterName) init { @@ -62,6 +62,6 @@ object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", no } override fun setup(context: CordformContext) { - ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it) }, advertisedService.type.id, clusterName) + ServiceIdentityGenerator.generateToDisk(notaryNames.map { context.baseDirectory(it.x500Name) }, advertisedService.type.id, clusterName) } } diff --git a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt index 46d1bf0ae6..82a73da758 100644 --- a/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt +++ b/samples/notary-demo/src/main/kotlin/net/corda/notarydemo/SingleNotaryCordform.kt @@ -19,7 +19,7 @@ fun main(args: Array) = SingleNotaryCordform.runNodes() val notaryDemoUser = User("demou", "demop", setOf(startFlowPermission(), startFlowPermission())) -object SingleNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", DUMMY_NOTARY.name) { +object SingleNotaryCordform : CordformDefinition("build" / "notary-demo-nodes", DUMMY_NOTARY.name.x500Name) { init { node { name(ALICE.name) diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 8a974f1ab2..29f427cb12 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -63,9 +63,9 @@ dependencies { task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { directory "./build/nodes" - networkMap "O=Notary Service,OU=corda,L=Zurich,C=CH" + networkMap "O=Notary Service,L=Zurich,C=CH" node { - name "O=Notary Service,OU=corda,L=Zurich,C=CH" + name "O=Notary Service,L=Zurich,C=CH" advertisedServices = ["corda.notary.validating"] p2pPort 10002 cordapps = ["net.corda:finance:$corda_release_version"] diff --git a/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt b/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt index 444e1aa7a8..6629570ebe 100644 --- a/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt +++ b/samples/simm-valuation-demo/src/integration-test/kotlin/net/corda/vega/SimmValuationTest.kt @@ -1,21 +1,21 @@ package net.corda.vega import com.opengamma.strata.product.common.BuySell +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.ServiceInfo import net.corda.core.utilities.getOrThrow +import net.corda.node.services.transactions.SimpleNotaryService import net.corda.testing.DUMMY_BANK_A import net.corda.testing.DUMMY_BANK_B import net.corda.testing.DUMMY_NOTARY -import net.corda.testing.driver.driver -import net.corda.node.services.transactions.SimpleNotaryService import net.corda.testing.IntegrationTestCategory +import net.corda.testing.driver.driver import net.corda.testing.http.HttpApi import net.corda.vega.api.PortfolioApi 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 @@ -52,7 +52,7 @@ class SimmValuationTest : IntegrationTestCategory { } } - private fun getPartyWithName(partyApi: HttpApi, counterparty: X500Name): PortfolioApi.ApiParty { + private fun getPartyWithName(partyApi: HttpApi, counterparty: CordaX500Name): PortfolioApi.ApiParty { return getAvailablePartiesFor(partyApi).counterparties.single { it.text == counterparty } } diff --git a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt index a5bd412d7a..2bd8ab0d28 100644 --- a/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt +++ b/samples/simm-valuation-demo/src/main/kotlin/net/corda/vega/api/PortfolioApi.kt @@ -5,6 +5,7 @@ import net.corda.core.contracts.StateAndRef import net.corda.core.utilities.parsePublicKeyBase58 import net.corda.core.utilities.toBase58String import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow @@ -242,7 +243,7 @@ class PortfolioApi(val rpc: CordaRPCOps) { } } - data class ApiParty(val id: String, val text: X500Name) + data class ApiParty(val id: String, val text: CordaX500Name) data class AvailableParties(val self: ApiParty, val counterparties: List) /** diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 36928a8807..216405f66f 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -51,9 +51,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { directory "./build/nodes" // This name "Notary" is hard-coded into TraderDemoClientApi so if you change it here, change it there too. // In this demo the node that runs a standalone notary also acts as the network map server. - networkMap "O=Notary Service,OU=corda,L=Zurich,C=CH" + networkMap "O=Notary Service,L=Zurich,C=CH" node { - name "O=Notary Service,OU=corda,L=Zurich,C=CH" + name "O=Notary Service,L=Zurich,C=CH" advertisedServices = ["corda.notary.validating"] p2pPort 10002 cordapps = ["net.corda:finance:$corda_release_version"] diff --git a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/TraderDemoClientApi.kt b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/TraderDemoClientApi.kt index 3f4b2e4520..9ac6d6d51f 100644 --- a/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/TraderDemoClientApi.kt +++ b/samples/trader-demo/src/main/kotlin/net/corda/traderdemo/TraderDemoClientApi.kt @@ -1,6 +1,7 @@ package net.corda.traderdemo import net.corda.core.contracts.Amount +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.Emoji import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow @@ -21,7 +22,6 @@ import net.corda.testing.DUMMY_NOTARY import net.corda.testing.contracts.calculateRandomlySizedAmounts import net.corda.traderdemo.flow.CommercialPaperIssueFlow import net.corda.traderdemo.flow.SellerFlow -import org.bouncycastle.asn1.x500.X500Name import java.util.* /** @@ -42,7 +42,7 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) { return rpc.vaultQueryBy(countCriteria).otherResults.single() as Long } - fun runIssuer(amount: Amount, buyerName: X500Name, sellerName: X500Name) { + fun runIssuer(amount: Amount, buyerName: CordaX500Name, sellerName: CordaX500Name) { val ref = OpaqueBytes.of(1) val buyer = rpc.partyFromX500Name(buyerName) ?: throw IllegalStateException("Don't know $buyerName") val seller = rpc.partyFromX500Name(sellerName) ?: throw IllegalStateException("Don't know $sellerName") @@ -75,7 +75,7 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) { println("Commercial paper issued to seller") } - fun runSeller(amount: Amount = 1000.0.DOLLARS, buyerName: X500Name) { + fun runSeller(amount: Amount = 1000.0.DOLLARS, buyerName: CordaX500Name) { val otherParty = rpc.partyFromX500Name(buyerName) ?: throw IllegalStateException("Don't know $buyerName") // The seller will sell some commercial paper to the buyer, who will pay with (self issued) cash. // diff --git a/testing/node-driver/src/main/kotlin/net/corda/demorun/DemoRunner.kt b/testing/node-driver/src/main/kotlin/net/corda/demorun/DemoRunner.kt index 2521dbee01..69406d4bee 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/demorun/DemoRunner.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/demorun/DemoRunner.kt @@ -2,6 +2,7 @@ package net.corda.demorun import net.corda.cordform.CordformDefinition import net.corda.cordform.CordformNode +import net.corda.core.identity.CordaX500Name import net.corda.testing.driver.NetworkMapStartStrategy import net.corda.testing.driver.PortAllocation import net.corda.testing.driver.driver @@ -17,7 +18,7 @@ fun CordformDefinition.clean() { fun CordformDefinition.runNodes() = driver( isDebug = true, driverDirectory = driverDirectory, - networkMapStartStrategy = NetworkMapStartStrategy.Nominated(networkMapNodeName), + networkMapStartStrategy = NetworkMapStartStrategy.Nominated(CordaX500Name.build(networkMapNodeName)), portAllocation = PortAllocation.Incremental(10001) ) { setup(this) diff --git a/testing/node-driver/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt index 6aa3cc1aa4..1ab7155e80 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt @@ -2,6 +2,7 @@ package net.corda.demorun.util import net.corda.cordform.CordformDefinition import net.corda.cordform.CordformNode +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.ServiceInfo import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.User @@ -11,7 +12,7 @@ fun CordformDefinition.node(configure: CordformNode.() -> Unit) { addNode { cordformNode -> cordformNode.configure() } } -fun CordformNode.name(name: X500Name) = name(name.toString()) +fun CordformNode.name(name: CordaX500Name) = name(name.toString()) fun CordformNode.rpcUsers(vararg users: User) { rpcUsers = users.map { it.toMap() } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt index daded934cb..9b8718bc40 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt @@ -4,16 +4,14 @@ package net.corda.testing import com.nhaarman.mockito_kotlin.spy import com.nhaarman.mockito_kotlin.whenever +import net.corda.core.identity.CordaX500Name import net.corda.core.node.ServiceHub import net.corda.core.transactions.TransactionBuilder -import net.corda.core.utilities.commonName -import net.corda.core.utilities.organisation import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.VerifierType import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties -import org.bouncycastle.asn1.x500.X500Name import java.net.URL import java.nio.file.Path @@ -52,7 +50,7 @@ import java.nio.file.Path fun testNodeConfiguration( baseDirectory: Path, - myLegalName: X500Name): NodeConfiguration { + myLegalName: CordaX500Name): NodeConfiguration { abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters. val nc = spy() whenever(nc.baseDirectory).thenReturn(baseDirectory) diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/RPCDriver.kt index 7a8aad45ca..5e64be47d5 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/RPCDriver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/RPCDriver.kt @@ -6,6 +6,7 @@ import net.corda.client.rpc.internal.RPCClient import net.corda.client.rpc.internal.RPCClientConfiguration import net.corda.core.concurrent.CordaFuture import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.concurrent.fork import net.corda.core.internal.concurrent.map import net.corda.core.internal.div @@ -42,7 +43,6 @@ import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy import org.apache.activemq.artemis.core.settings.impl.AddressSettings import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3 -import org.bouncycastle.asn1.x500.X500Name import java.lang.reflect.Method import java.nio.file.Path import java.nio.file.Paths @@ -60,7 +60,7 @@ interface RPCDriverExposedDSLInterface : DriverDSLExposedInterface { */ fun startInVmRpcServer( rpcUser: User = rpcTestUser, - nodeLegalName: X500Name = fakeNodeLegalName, + nodeLegalName: CordaX500Name = fakeNodeLegalName, maxFileSize: Int = ArtemisMessagingServer.MAX_FILE_SIZE, maxBufferedBytesPerClient: Long = 10L * ArtemisMessagingServer.MAX_FILE_SIZE, configuration: RPCServerConfiguration = RPCServerConfiguration.default, @@ -105,7 +105,7 @@ interface RPCDriverExposedDSLInterface : DriverDSLExposedInterface { fun startRpcServer( serverName: String = "driver-rpc-server-${random63BitValue()}", rpcUser: User = rpcTestUser, - nodeLegalName: X500Name = fakeNodeLegalName, + nodeLegalName: CordaX500Name = fakeNodeLegalName, maxFileSize: Int = ArtemisMessagingServer.MAX_FILE_SIZE, maxBufferedBytesPerClient: Long = 10L * ArtemisMessagingServer.MAX_FILE_SIZE, configuration: RPCServerConfiguration = RPCServerConfiguration.default, @@ -174,7 +174,7 @@ interface RPCDriverExposedDSLInterface : DriverDSLExposedInterface { fun startRpcServerWithBrokerRunning( rpcUser: User = rpcTestUser, - nodeLegalName: X500Name = fakeNodeLegalName, + nodeLegalName: CordaX500Name = fakeNodeLegalName, configuration: RPCServerConfiguration = RPCServerConfiguration.default, ops: I, brokerHandle: RpcBrokerHandle @@ -211,7 +211,7 @@ data class RpcServerHandle( ) val rpcTestUser = User("user1", "test", permissions = emptySet()) -val fakeNodeLegalName = X500Name("CN=not:a:valid:name") +val fakeNodeLegalName = CordaX500Name(organisation = "Not:a:real:name", locality = "Nowhere", country = "GB") // Use a global pool so that we can run RPC tests in parallel private val globalPortAllocation = PortAllocation.Incremental(10000) @@ -327,7 +327,7 @@ data class RPCDriverDSL( override fun startInVmRpcServer( rpcUser: User, - nodeLegalName: X500Name, + nodeLegalName: CordaX500Name, maxFileSize: Int, maxBufferedBytesPerClient: Long, configuration: RPCServerConfiguration, @@ -364,7 +364,7 @@ data class RPCDriverDSL( override fun startRpcServer( serverName: String, rpcUser: User, - nodeLegalName: X500Name, + nodeLegalName: CordaX500Name, maxFileSize: Int, maxBufferedBytesPerClient: Long, configuration: RPCServerConfiguration, @@ -460,7 +460,7 @@ data class RPCDriverDSL( override fun startRpcServerWithBrokerRunning( rpcUser: User, - nodeLegalName: X500Name, + nodeLegalName: CordaX500Name, configuration: RPCServerConfiguration, ops: I, brokerHandle: RpcBrokerHandle diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt index a704ad5646..5c410218cd 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt @@ -11,6 +11,7 @@ import net.corda.cordform.CordformNode import net.corda.cordform.NodeDefinition import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.firstOf +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.ThreadBox import net.corda.core.internal.concurrent.* @@ -88,7 +89,7 @@ interface DriverDSLExposedInterface : CordformContext { */ fun startNode( defaultParameters: NodeParameters = NodeParameters(), - providedName: X500Name? = defaultParameters.providedName, + providedName: CordaX500Name? = defaultParameters.providedName, advertisedServices: Set = defaultParameters.advertisedServices, rpcUsers: List = defaultParameters.rpcUsers, verifierType: VerifierType = defaultParameters.verifierType, @@ -124,7 +125,7 @@ interface DriverDSLExposedInterface : CordformContext { * @return The [Party] identity of the distributed notary service, and the [NodeInfo]s of the notaries in the cluster. */ fun startNotaryCluster( - notaryName: X500Name, + notaryName: CordaX500Name, clusterSize: Int = 3, type: ServiceType = RaftValidatingNotaryService.type, verifierType: VerifierType = VerifierType.InMemory, @@ -252,14 +253,14 @@ sealed class PortAllocation { * Helper builder for configuring a [node] from Java. */ data class NodeParameters( - val providedName: X500Name? = null, + val providedName: CordaX500Name? = null, val advertisedServices: Set = emptySet(), val rpcUsers: List = emptyList(), val verifierType: VerifierType = VerifierType.InMemory, val customOverrides: Map = emptyMap(), val startInSameProcess: Boolean? = null ) { - fun setProvidedName(providedName: X500Name?) = copy(providedName = providedName) + fun setProvidedName(providedName: CordaX500Name?) = copy(providedName = providedName) fun setAdvertisedServices(advertisedServices: Set) = copy(advertisedServices = advertisedServices) fun setRpcUsers(rpcUsers: List) = copy(rpcUsers = rpcUsers) fun setVerifierType(verifierType: VerifierType) = copy(verifierType = verifierType) @@ -641,19 +642,19 @@ class DriverDSL( } } - private fun networkMapServiceConfigLookup(networkMapCandidates: List): (X500Name) -> Map? { + private fun networkMapServiceConfigLookup(networkMapCandidates: List): (CordaX500Name) -> Map? { return networkMapStartStrategy.run { when (this) { is NetworkMapStartStrategy.Dedicated -> { serviceConfig(dedicatedNetworkMapAddress).let { - { _: X500Name -> it } + { _: CordaX500Name -> it } } } is NetworkMapStartStrategy.Nominated -> { serviceConfig(networkMapCandidates.filter { it.name == legalName.toString() }.single().config.getString("p2pAddress").parseNetworkHostAndPort()).let { - { nodeName: X500Name -> if (nodeName == legalName) null else it } + { nodeName: CordaX500Name -> if (nodeName == legalName) null else it } } } } @@ -662,7 +663,7 @@ class DriverDSL( override fun startNode( defaultParameters: NodeParameters, - providedName: X500Name?, + providedName: CordaX500Name?, advertisedServices: Set, rpcUsers: List, verifierType: VerifierType, @@ -673,13 +674,13 @@ class DriverDSL( val rpcAddress = portAllocation.nextHostAndPort() val webAddress = portAllocation.nextHostAndPort() // TODO: Derive name from the full picked name, don't just wrap the common name - val name = providedName ?: getX500Name(O = "${oneOf(names).organisation}-${p2pAddress.port}", L = "London", C = "GB") + val name = providedName ?: CordaX500Name(organisation = "${oneOf(names).organisation}-${p2pAddress.port}", locality = "London", country = "GB") val networkMapServiceConfigLookup = networkMapServiceConfigLookup(listOf(object : NodeDefinition { override fun getName() = name.toString() override fun getConfig() = configOf("p2pAddress" to p2pAddress.toString()) })) val config = ConfigHelper.loadConfig( - baseDirectory = baseDirectory(name), + baseDirectory = baseDirectory(name.x500Name), allowMissingConfig = true, configOverrides = configOf( "myLegalName" to name.toString(), @@ -701,10 +702,10 @@ class DriverDSL( return nodes.map { node -> portAllocation.nextHostAndPort() // rpcAddress val webAddress = portAllocation.nextHostAndPort() - val name = X500Name(node.name) + val name = CordaX500Name.parse(node.name) val config = ConfigHelper.loadConfig( - baseDirectory = baseDirectory(name), + baseDirectory = baseDirectory(name.x500Name), allowMissingConfig = true, configOverrides = node.config + mapOf( "extraAdvertisedServiceIds" to node.advertisedServices, @@ -718,15 +719,15 @@ class DriverDSL( } override fun startNotaryCluster( - notaryName: X500Name, + notaryName: CordaX500Name, clusterSize: Int, type: ServiceType, verifierType: VerifierType, rpcUsers: List, startInSameProcess: Boolean? ): CordaFuture>> { - val nodeNames = (0 until clusterSize).map { getX500Name(O = "Notary Service $it", OU = "corda", L = "Zurich", C = "CH") } - val paths = nodeNames.map { baseDirectory(it) } + val nodeNames = (0 until clusterSize).map { CordaX500Name(organisation = "Notary Service $it", locality = "Zurich", country = "CH") } + val paths = nodeNames.map { baseDirectory(it.x500Name) } ServiceIdentityGenerator.generateToDisk(paths, type.id, notaryName) val advertisedServices = setOf(ServiceInfo(type, notaryName)) val notaryClusterAddress = portAllocation.nextHostAndPort() @@ -791,13 +792,16 @@ class DriverDSL( } } - override fun baseDirectory(nodeName: X500Name): Path = driverDirectory / nodeName.organisation.replace(WHITESPACE, "") + override fun baseDirectory(nodeName: X500Name): Path { + val nodeDirectoryName = String(nodeName.organisation.filter { !it.isWhitespace() }.toCharArray()) + return driverDirectory / nodeDirectoryName + } override fun startDedicatedNetworkMapService(startInProcess: Boolean?): CordaFuture { val webAddress = portAllocation.nextHostAndPort() val networkMapLegalName = networkMapStartStrategy.legalName val config = ConfigHelper.loadConfig( - baseDirectory = baseDirectory(networkMapLegalName), + baseDirectory = baseDirectory(networkMapLegalName.x500Name), allowMissingConfig = true, configOverrides = configOf( "myLegalName" to networkMapLegalName.toString(), diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt index e185930198..0086884c77 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt @@ -1,12 +1,12 @@ package net.corda.testing.driver +import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.NetworkHostAndPort import net.corda.testing.DUMMY_MAP -import org.bouncycastle.asn1.x500.X500Name sealed class NetworkMapStartStrategy { internal abstract val startDedicated: Boolean - internal abstract val legalName: X500Name + internal abstract val legalName: CordaX500Name internal fun serviceConfig(address: NetworkHostAndPort) = mapOf( "address" to address.toString(), "legalName" to legalName.toString() @@ -17,7 +17,7 @@ sealed class NetworkMapStartStrategy { override val legalName = DUMMY_MAP.name } - class Nominated(override val legalName: X500Name) : NetworkMapStartStrategy() { + class Nominated(override val legalName: CordaX500Name) : NetworkMapStartStrategy() { override val startDedicated = false } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt index 886043b644..61961aa4fc 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt @@ -3,7 +3,7 @@ package net.corda.testing.node import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.SettableFuture -import net.corda.core.utilities.getX500Name +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.ThreadBox import net.corda.core.messaging.AllPossibleRecipients import net.corda.core.messaging.MessageRecipientGroup @@ -20,7 +20,6 @@ import net.corda.node.utilities.AffinityExecutor import net.corda.node.utilities.CordaPersistence import net.corda.testing.node.InMemoryMessagingNetwork.InMemoryMessaging import org.apache.activemq.artemis.utils.ReusableLatch -import org.bouncycastle.asn1.x500.X500Name import org.slf4j.LoggerFactory import rx.Observable import rx.subjects.PublishSubject @@ -80,8 +79,8 @@ class InMemoryMessagingNetwork( // Holds the mapping from services to peers advertising the service. private val serviceToPeersMapping = HashMap>() - // Holds the mapping from node's X500Name to PeerHandle. - private val peersMapping = HashMap() + // Holds the mapping from node's X.500 name to PeerHandle. + private val peersMapping = HashMap() @Suppress("unused") // Used by the visualiser tool. /** A stream of (sender, message, recipients) triples */ @@ -127,7 +126,7 @@ class InMemoryMessagingNetwork( id: Int, executor: AffinityExecutor, advertisedServices: List, - description: X500Name = getX500Name(O = "In memory node $id", L = "London", C = "UK"), + description: CordaX500Name = CordaX500Name(organisation = "In memory node $id", locality = "London", country = "UK"), database: CordaPersistence) : MessagingServiceBuilder { val peerHandle = PeerHandle(id, description) @@ -200,7 +199,7 @@ class InMemoryMessagingNetwork( } @CordaSerializable - data class PeerHandle(val id: Int, val description: X500Name) : SingleMessageRecipient { + data class PeerHandle(val id: Int, val description: CordaX500Name) : SingleMessageRecipient { override fun toString() = description.toString() override fun equals(other: Any?) = other is PeerHandle && other.id == id override fun hashCode() = id.hashCode() @@ -289,7 +288,7 @@ class InMemoryMessagingNetwork( override val platformVersion: Int, override val uniqueMessageId: UUID, override val debugTimestamp: Instant, - override val peer: X500Name) : ReceivedMessage + override val peer: CordaX500Name) : ReceivedMessage /** * An [InMemoryMessaging] provides a [MessagingService] that isn't backed by any kind of network or disk storage diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt index 45ac7ae63b..c95492fc03 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt @@ -2,12 +2,12 @@ package net.corda.testing.node import co.paralleluniverse.common.util.VisibleForTesting import net.corda.core.crypto.entropyToKeyPair +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NonEmptySet -import net.corda.core.utilities.getX500Name import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.network.PersistentNetworkMapCache import net.corda.testing.getTestPartyAndCertificate @@ -20,8 +20,8 @@ import java.math.BigInteger */ class MockNetworkMapCache(serviceHub: ServiceHubInternal) : PersistentNetworkMapCache(serviceHub) { private companion object { - val BANK_C = getTestPartyAndCertificate(getX500Name(O = "Bank C", L = "London", C = "GB"), entropyToKeyPair(BigInteger.valueOf(1000)).public) - val BANK_D = getTestPartyAndCertificate(getX500Name(O = "Bank D", L = "London", C = "GB"), entropyToKeyPair(BigInteger.valueOf(2000)).public) + val BANK_C = getTestPartyAndCertificate(CordaX500Name(organisation = "Bank C", locality = "London", country = "GB"), entropyToKeyPair(BigInteger.valueOf(1000)).public) + val BANK_D = getTestPartyAndCertificate(CordaX500Name(organisation = "Bank D", locality = "London", country = "GB"), entropyToKeyPair(BigInteger.valueOf(2000)).public) val BANK_C_ADDR = NetworkHostAndPort("bankC", 8080) val BANK_D_ADDR = NetworkHostAndPort("bankD", 8080) } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt index d59836ecf6..4883aaba4b 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -5,6 +5,7 @@ import com.google.common.jimfs.Jimfs import com.nhaarman.mockito_kotlin.whenever import net.corda.core.crypto.entropyToKeyPair import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.concurrent.doneFuture import net.corda.core.internal.createDirectories @@ -31,7 +32,6 @@ import net.corda.node.utilities.CertificateAndKeyPair import net.corda.testing.* import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import org.apache.activemq.artemis.utils.ReusableLatch -import org.bouncycastle.asn1.x500.X500Name import org.slf4j.Logger import java.math.BigInteger import java.nio.file.Path @@ -288,7 +288,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, * @param configOverrides add/override behaviour of the [NodeConfiguration] mock object. */ fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int? = null, - start: Boolean = true, legalName: X500Name? = null, overrideServices: Map? = null, + start: Boolean = true, legalName: CordaX500Name? = null, overrideServices: Map? = null, entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), vararg advertisedServices: ServiceInfo, configOverrides: (NodeConfiguration) -> Any? = {}): MockNode { @@ -297,14 +297,14 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, /** Like the other [createNode] but takes a [Factory] and propagates its [MockNode] subtype. */ fun createNode(networkMapAddress: SingleMessageRecipient? = null, forcedID: Int? = null, nodeFactory: Factory, - start: Boolean = true, legalName: X500Name? = null, overrideServices: Map? = null, + start: Boolean = true, legalName: CordaX500Name? = null, overrideServices: Map? = null, entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), vararg advertisedServices: ServiceInfo, configOverrides: (NodeConfiguration) -> Any? = {}): N { val id = forcedID ?: nextNodeId++ val config = testNodeConfiguration( baseDirectory = baseDirectory(id).createDirectories(), - myLegalName = legalName ?: getX500Name(O = "Mock Company $id", L = "London", C = "GB")).also { + myLegalName = legalName ?: CordaX500Name(organisation = "Mock Company $id", locality = "London", country = "GB")).also { whenever(it.dataSourceProperties).thenReturn(makeTestDataSourceProperties("node_${id}_net_$networkId")) configOverrides(it) } @@ -369,15 +369,15 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, } fun createNotaryNode(networkMapAddress: SingleMessageRecipient? = null, - legalName: X500Name? = null, + legalName: CordaX500Name? = null, overrideServices: Map? = null, - serviceName: X500Name? = null): MockNode { + serviceName: CordaX500Name? = null): MockNode { return createNode(networkMapAddress, legalName = legalName, overrideServices = overrideServices, advertisedServices = *arrayOf(ServiceInfo(NetworkMapService.type), ServiceInfo(ValidatingNotaryService.type, serviceName))) } fun createPartyNode(networkMapAddress: SingleMessageRecipient, - legalName: X500Name? = null, + legalName: CordaX500Name? = null, overrideServices: Map? = null): MockNode { return createNode(networkMapAddress, legalName = legalName, overrideServices = overrideServices) } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt index 2d5366a17f..eb39cfea62 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt @@ -1,12 +1,15 @@ package net.corda.testing.node import net.corda.core.concurrent.CordaFuture +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.concurrent.* import net.corda.core.internal.createDirectories import net.corda.core.internal.div import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType -import net.corda.core.utilities.* +import net.corda.core.utilities.getOrThrow +import net.corda.core.utilities.getX500Name +import net.corda.core.utilities.organisation import net.corda.node.internal.Node import net.corda.node.services.config.ConfigHelper import net.corda.node.services.config.FullNodeConfiguration @@ -37,6 +40,8 @@ import kotlin.concurrent.thread */ // TODO Some of the logic here duplicates what's in the driver abstract class NodeBasedTest : TestDependencyInjectionBase() { + val WHITESPACE = "\\s++".toRegex() + @Rule @JvmField val tempFolder = TemporaryFolder() @@ -81,7 +86,7 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { * 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: X500Name = DUMMY_MAP.name, + fun startNetworkMapNode(legalName: CordaX500Name = DUMMY_MAP.name, platformVersion: Int = 1, advertisedServices: Set = emptySet(), rpcUsers: List = emptyList(), @@ -93,7 +98,7 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { } @JvmOverloads - fun startNode(legalName: X500Name, + fun startNode(legalName: CordaX500Name, platformVersion: Int = 1, advertisedServices: Set = emptySet(), rpcUsers: List = emptyList(), @@ -126,7 +131,7 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { return if (waitForConnection) node.nodeReadyFuture.map { node } else doneFuture(node) } - fun startNotaryCluster(notaryName: X500Name, + fun startNotaryCluster(notaryName: CordaX500Name, clusterSize: Int, serviceType: ServiceType = RaftValidatingNotaryService.type): CordaFuture> { ServiceIdentityGenerator.generateToDisk( @@ -138,14 +143,14 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { val nodeAddresses = getFreeLocalPorts("localhost", clusterSize).map { it.toString() } val masterNodeFuture = startNode( - getX500Name(O = "${notaryName.organisation}-0", L = notaryName.locality, C = notaryName.country), + CordaX500Name(organisation = "${notaryName.organisation}-0", locality = notaryName.locality, country = notaryName.country), advertisedServices = setOf(serviceInfo), configOverrides = mapOf("notaryNodeAddress" to nodeAddresses[0], "database" to mapOf("serverNameTablePrefix" to if (clusterSize > 1) "${notaryName.organisation}0".replace(Regex("[^0-9A-Za-z]+"), "") else ""))) val remainingNodesFutures = (1 until clusterSize).map { startNode( - getX500Name(O = "${notaryName.organisation}-$it", L = notaryName.locality, C = notaryName.country), + CordaX500Name(organisation = "${notaryName.organisation}-$it", locality = notaryName.locality, country = notaryName.country), advertisedServices = setOf(serviceInfo), configOverrides = mapOf( "notaryNodeAddress" to nodeAddresses[it], @@ -160,13 +165,13 @@ abstract class NodeBasedTest : TestDependencyInjectionBase() { protected fun baseDirectory(legalName: X500Name) = tempFolder.root.toPath() / legalName.organisation.replace(WHITESPACE, "") - private fun startNodeInternal(legalName: X500Name, + private fun startNodeInternal(legalName: CordaX500Name, platformVersion: Int, advertisedServices: Set, rpcUsers: List, configOverrides: Map, noNetworkMap: Boolean = false): Node { - val baseDirectory = baseDirectory(legalName).createDirectories() + val baseDirectory = baseDirectory(legalName.x500Name).createDirectories() val localPort = getFreeLocalPorts("localhost", 2) val p2pAddress = configOverrides["p2pAddress"] ?: localPort[0].toString() val config = ConfigHelper.loadConfig( diff --git a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt index 71ad5805ba..ef0c1ff87b 100644 --- a/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt +++ b/testing/smoke-test-utils/src/main/kotlin/net/corda/smoketesting/NodeConfig.kt @@ -5,12 +5,11 @@ import com.typesafe.config.ConfigFactory.empty import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigValue import com.typesafe.config.ConfigValueFactory -import net.corda.core.utilities.organisation +import net.corda.core.identity.CordaX500Name import net.corda.nodeapi.User -import org.bouncycastle.asn1.x500.X500Name class NodeConfig( - val legalName: X500Name, + val legalName: CordaX500Name, val p2pPort: Int, val rpcPort: Int, val webPort: Int, diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 9262a697d7..1c53d981f4 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -6,6 +6,7 @@ package net.corda.testing import net.corda.core.contracts.StateRef import net.corda.core.crypto.SecureHash import net.corda.core.crypto.generateKeyPair +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.core.node.services.IdentityService @@ -18,7 +19,6 @@ import net.corda.node.utilities.CertificateType import net.corda.node.utilities.X509Utilities import net.corda.nodeapi.config.SSLConfiguration import net.corda.nodeapi.internal.serialization.AMQP_ENABLED -import org.bouncycastle.asn1.x500.X500Name import java.nio.file.Files import java.security.KeyPair import java.security.PublicKey @@ -59,20 +59,20 @@ val ALICE_PUBKEY: PublicKey get() = ALICE_KEY.public val BOB_PUBKEY: PublicKey get() = BOB_KEY.public val CHARLIE_PUBKEY: PublicKey get() = CHARLIE_KEY.public -val MEGA_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(getX500Name(O = "MegaCorp", L = "London", C = "GB"), MEGA_CORP_PUBKEY) +val MEGA_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(CordaX500Name(organisation = "MegaCorp", locality = "London", country = "GB"), MEGA_CORP_PUBKEY) val MEGA_CORP: Party get() = MEGA_CORP_IDENTITY.party -val MINI_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(getX500Name(O = "MiniCorp", L = "London", C = "GB"), MINI_CORP_PUBKEY) +val MINI_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(CordaX500Name(organisation = "MiniCorp", locality = "London", country = "GB"), MINI_CORP_PUBKEY) val MINI_CORP: Party get() = MINI_CORP_IDENTITY.party val BOC_KEY: KeyPair by lazy { generateKeyPair() } val BOC_PUBKEY: PublicKey get() = BOC_KEY.public -val BOC_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(getX500Name(O = "BankOfCorda", L = "London", C = "GB"), BOC_PUBKEY) +val BOC_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(CordaX500Name(organisation = "BankOfCorda", locality = "London", country = "GB"), BOC_PUBKEY) val BOC: Party get() = BOC_IDENTITY.party val BOC_PARTY_REF = BOC.ref(OpaqueBytes.of(1)).reference val BIG_CORP_KEY: KeyPair by lazy { generateKeyPair() } val BIG_CORP_PUBKEY: PublicKey get() = BIG_CORP_KEY.public -val BIG_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(getX500Name(O = "BigCorporation", L = "London", C = "GB"), BIG_CORP_PUBKEY) +val BIG_CORP_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(CordaX500Name(organisation = "BigCorporation", locality = "London", country = "GB"), BIG_CORP_PUBKEY) val BIG_CORP: Party get() = BIG_CORP_IDENTITY.party val BIG_CORP_PARTY_REF = BIG_CORP.ref(OpaqueBytes.of(1)).reference @@ -116,7 +116,7 @@ fun getFreeLocalPorts(hostName: String, numberToAlloc: Int): List amqpSpecific(reason: String, function: () -> Unit) function() } else { loggerFor().info("Ignoring AMQP specific test, reason: $reason" ) -} \ No newline at end of file +} diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt index 2618406cd9..bb75d25961 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt @@ -6,6 +6,7 @@ import net.corda.core.contracts.Command import net.corda.core.contracts.TypeOnlyCommandData import net.corda.core.crypto.entropyToKeyPair import net.corda.core.crypto.generateKeyPair +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate import net.corda.node.utilities.CertificateAndKeyPair @@ -25,42 +26,42 @@ val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() } val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) } /** Dummy notary identity for tests and simulations */ val DUMMY_NOTARY_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(DUMMY_NOTARY) -val DUMMY_NOTARY: Party get() = Party(getX500Name(O = "Notary Service", OU = "corda", L = "Zurich", C = "CH"), DUMMY_NOTARY_KEY.public) +val DUMMY_NOTARY: Party get() = Party(CordaX500Name(organisation = "Notary Service", locality = "Zurich", country = "CH"), DUMMY_NOTARY_KEY.public) val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) } /** Dummy network map service identity for tests and simulations */ -val DUMMY_MAP: Party get() = Party(getX500Name(O = "Network Map Service", OU = "corda", L = "Amsterdam", C = "NL"), DUMMY_MAP_KEY.public) +val DUMMY_MAP: Party get() = Party(CordaX500Name(organisation = "Network Map Service", locality = "Amsterdam", country = "NL"), DUMMY_MAP_KEY.public) val DUMMY_BANK_A_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(40)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_A: Party get() = Party(getX500Name(O = "Bank A", L = "London", C = "GB"), DUMMY_BANK_A_KEY.public) +val DUMMY_BANK_A: Party get() = Party(CordaX500Name(organisation = "Bank A", locality = "London", country = "GB"), DUMMY_BANK_A_KEY.public) val DUMMY_BANK_B_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(50)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_B: Party get() = Party(getX500Name(O = "Bank B", L = "New York", C = "US"), DUMMY_BANK_B_KEY.public) +val DUMMY_BANK_B: Party get() = Party(CordaX500Name(organisation = "Bank B", locality = "New York", country = "US"), DUMMY_BANK_B_KEY.public) val DUMMY_BANK_C_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(60)) } /** Dummy bank identity for tests and simulations */ -val DUMMY_BANK_C: Party get() = Party(getX500Name(O = "Bank C", L = "Tokyo", C = "JP"), DUMMY_BANK_C_KEY.public) +val DUMMY_BANK_C: Party get() = Party(CordaX500Name(organisation = "Bank C", locality = "Tokyo", country = "JP"), DUMMY_BANK_C_KEY.public) val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) } /** Dummy individual identity for tests and simulations */ val ALICE_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(ALICE) -val ALICE: Party get() = Party(getX500Name(O = "Alice Corp", L = "Madrid", C = "ES"), ALICE_KEY.public) +val ALICE: Party get() = Party(CordaX500Name(organisation = "Alice Corp", locality = "Madrid", country = "ES"), ALICE_KEY.public) val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) } /** Dummy individual identity for tests and simulations */ val BOB_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(BOB) -val BOB: Party get() = Party(getX500Name(O = "Bob Plc", L = "Rome", C = "IT"), BOB_KEY.public) +val BOB: Party get() = Party(CordaX500Name(organisation = "Bob Plc", locality = "Rome", country = "IT"), BOB_KEY.public) val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) } /** Dummy individual identity for tests and simulations */ val CHARLIE_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(CHARLIE) -val CHARLIE: Party get() = Party(getX500Name(O = "Charlie Ltd", L = "Athens", C = "GR"), CHARLIE_KEY.public) +val CHARLIE: Party get() = Party(CordaX500Name(organisation = "Charlie Ltd", locality = "Athens", country = "GR"), CHARLIE_KEY.public) val DUMMY_REGULATOR_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(100)) } /** Dummy regulator for tests and simulations */ -val DUMMY_REGULATOR: Party get() = Party(getX500Name(O = "Regulator A", OU = "Corda", L = "Paris", C = "FR"), DUMMY_REGULATOR_KEY.public) +val DUMMY_REGULATOR: Party get() = Party(CordaX500Name(organisation = "Regulator A", locality = "Paris", country = "FR"), DUMMY_REGULATOR_KEY.public) val DUMMY_CA_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(110)) } val DUMMY_CA: CertificateAndKeyPair by lazy { @@ -74,4 +75,4 @@ fun dummyCommand(vararg signers: PublicKey = arrayOf(generateKeyPair().public) ) object DummyCommandData : TypeOnlyCommandData() val DUMMY_IDENTITY_1: PartyAndCertificate get() = getTestPartyAndCertificate(DUMMY_PARTY) -val DUMMY_PARTY: Party get() = Party(getX500Name(O = "Dummy", L = "Madrid", C = "ES"), DUMMY_KEY_1.public) +val DUMMY_PARTY: Party get() = Party(CordaX500Name(organisation = "Dummy", locality = "Madrid", country = "ES"), DUMMY_KEY_1.public) diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt index c14b750e0c..15115b67fd 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/messaging/SimpleMQClient.kt @@ -1,7 +1,7 @@ package net.corda.testing.messaging +import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getX500Name import net.corda.nodeapi.ArtemisMessagingComponent import net.corda.nodeapi.ArtemisTcpTransport import net.corda.nodeapi.ConnectionDirection @@ -15,8 +15,9 @@ import org.apache.activemq.artemis.api.core.client.* class SimpleMQClient(val target: NetworkHostAndPort, override val config: SSLConfiguration? = configureTestSSL(DEFAULT_MQ_LEGAL_NAME)) : ArtemisMessagingComponent() { companion object { - val DEFAULT_MQ_LEGAL_NAME = getX500Name(O = "SimpleMQClient", OU = "corda", L = "London", C = "GB") + val DEFAULT_MQ_LEGAL_NAME = CordaX500Name(organisation = "SimpleMQClient", locality = "London", country = "GB") } + lateinit var sessionFactory: ClientSessionFactory lateinit var session: ClientSession lateinit var producer: ClientProducer diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt index 1bf02e2a52..f6a2c46f71 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/InstallFactory.kt @@ -1,10 +1,10 @@ package net.corda.demobench.model import com.typesafe.config.Config +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.utilities.parseNetworkHostAndPort -import org.bouncycastle.asn1.x500.X500Name import tornadofx.* import java.io.IOException import java.nio.file.Files @@ -21,7 +21,7 @@ class InstallFactory : Controller() { val rpcPort = config.parsePort("rpcAddress") val webPort = config.parsePort("webAddress") val h2Port = config.getInt("h2port") - val x500name = X500Name(config.getString("myLegalName")) + val x500name = CordaX500Name.parse(config.getString("myLegalName")) val extraServices = config.parseExtraServices("extraAdvertisedServiceIds") val tempDir = Files.createTempDirectory(baseDir, ".node") @@ -38,7 +38,7 @@ class InstallFactory : Controller() { if (config.hasPath("networkMapService")) { val nmap = config.getConfig("networkMapService") - nodeConfig.networkMap = NetworkMapConfig(X500Name(nmap.getString("legalName")), nmap.parsePort("address")) + nodeConfig.networkMap = NetworkMapConfig(CordaX500Name.parse(nmap.getString("legalName")), nmap.parsePort("address")) } else { log.info("Node '${nodeConfig.legalName}' is the network map") } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt index 4aaccb3558..3960ee9a24 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt @@ -1,12 +1,10 @@ package net.corda.demobench.model -import net.corda.core.utilities.organisation -import net.corda.core.utilities.WHITESPACE -import org.bouncycastle.asn1.x500.X500Name +import net.corda.core.identity.CordaX500Name -open class NetworkMapConfig(val legalName: X500Name, val p2pPort: Int) { +open class NetworkMapConfig(val legalName: CordaX500Name, val p2pPort: Int) { val key: String = legalName.organisation.toKey() } -fun String.stripWhitespace() = replace(WHITESPACE, "") +fun String.stripWhitespace() = String(this.filter { !it.isWhitespace() }.toCharArray()) fun String.toKey() = stripWhitespace().toLowerCase() diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index 275ce76a45..b75ad5646a 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -1,6 +1,7 @@ package net.corda.demobench.model import com.typesafe.config.* +import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.locality import net.corda.nodeapi.User import org.bouncycastle.asn1.x500.X500Name @@ -11,7 +12,7 @@ import java.nio.file.StandardCopyOption class NodeConfig( baseDir: Path, - legalName: X500Name, + legalName: CordaX500Name, p2pPort: Int, val rpcPort: Int, val webPort: Int, diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt index 8fdb371618..72adb34d53 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt @@ -1,8 +1,8 @@ package net.corda.demobench.model +import net.corda.core.identity.CordaX500Name import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType -import net.corda.core.utilities.getX500Name import net.corda.demobench.plugin.PluginController import net.corda.demobench.pty.R3Pty import tornadofx.* @@ -54,10 +54,10 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() { val location = nodeData.nearestCity.value val config = NodeConfig( baseDir, - getX500Name( - O = nodeData.legalName.value.trim(), - L = location.description, - C = location.countryCode + CordaX500Name( + organisation = nodeData.legalName.value.trim(), + locality = location.description, + country = location.countryCode ), nodeData.p2pPort.value, nodeData.rpcPort.value, diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt index 869adc5735..afc91bb6f4 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt @@ -4,16 +4,15 @@ import com.jediterm.terminal.ui.JediTermWidget import com.jediterm.terminal.ui.UIUtil import com.jediterm.terminal.ui.settings.SettingsProvider import com.pty4j.PtyProcess +import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.loggerFor -import net.corda.core.utilities.organisation -import org.bouncycastle.asn1.x500.X500Name import java.awt.Dimension import java.io.IOException import java.nio.charset.StandardCharsets.UTF_8 import java.util.concurrent.Executors import java.util.concurrent.TimeUnit.SECONDS -class R3Pty(val name: X500Name, settings: SettingsProvider, dimension: Dimension, val onExit: (Int) -> Unit) : AutoCloseable { +class R3Pty(val name: CordaX500Name, settings: SettingsProvider, dimension: Dimension, val onExit: (Int) -> Unit) : AutoCloseable { private companion object { val log = loggerFor() } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt index 3597b530e2..16fe779134 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt @@ -14,15 +14,9 @@ import javafx.scene.layout.Pane import javafx.scene.layout.Priority import javafx.stage.FileChooser import javafx.util.StringConverter -import net.corda.core.internal.div -import net.corda.core.internal.exists -import net.corda.core.internal.readAllLines -import net.corda.core.internal.writeLines +import net.corda.core.internal.* import net.corda.core.node.CityDatabase import net.corda.core.node.WorldMapLocation -import net.corda.core.utilities.normaliseLegalName -import net.corda.core.utilities.organisation -import net.corda.core.utilities.validateLegalName import net.corda.demobench.model.* import net.corda.demobench.ui.CloseableTab import org.controlsfx.control.CheckListView @@ -194,11 +188,11 @@ class NodeTabView : Fragment() { validator { if (it == null) { error("Node name is required") - } else if (nodeController.nameExists(normaliseLegalName(it))) { + } else if (nodeController.nameExists(LegalNameValidator.normaliseLegalName(it))) { error("Node with this name already exists") } else { try { - validateLegalName(normaliseLegalName(it)) + LegalNameValidator.validateLegalName(LegalNameValidator.normaliseLegalName(it)) null } catch (e: IllegalArgumentException) { error(e.message) diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt index e5a8bff1fd..a19fcbc484 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt @@ -15,7 +15,6 @@ import javafx.scene.layout.VBox import javafx.util.Duration import net.corda.core.concurrent.match import net.corda.core.contracts.ContractState -import net.corda.core.utilities.organisation import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.vaultTrackBy import net.corda.core.node.services.vault.PageSpecification diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt index 324d09aa9c..0c9892f340 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NetworkMapConfigTest.kt @@ -1,14 +1,16 @@ package net.corda.demobench.model +import net.corda.core.identity.CordaX500Name import org.bouncycastle.asn1.x500.X500Name +import org.junit.Ignore import org.junit.Test import kotlin.test.assertEquals class NetworkMapConfigTest { - + @Ignore("This has been superseded by validation logic in CordaX500Name") @Test fun keyValue() { - val config = NetworkMapConfig(X500Name("O=My\tNasty Little\rLabel\n"), 10000) + val config = NetworkMapConfig(CordaX500Name.parse("O=My\tNasty Little\rLabel\n,L=London,C=GB"), 10000) assertEquals("mynastylittlelabel", config.key) } diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt index db2b61410c..3e6604d941 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeConfigTest.kt @@ -5,16 +5,15 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigValueFactory +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.div import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getX500Name import net.corda.node.internal.NetworkMapInfo import net.corda.node.services.config.FullNodeConfiguration import net.corda.nodeapi.User import net.corda.nodeapi.config.parseAs import net.corda.testing.DUMMY_NOTARY import net.corda.webserver.WebServerConfig -import org.bouncycastle.asn1.x500.X500Name import org.junit.Test import java.io.StringWriter import java.nio.file.Path @@ -29,7 +28,7 @@ class NodeConfigTest { companion object { private val baseDir: Path = Paths.get(".").toAbsolutePath() - private val myLegalName = getX500Name(OU = "Corda QA Department", O = "My Name", L = "New York", C = "US") + private val myLegalName = CordaX500Name(organisation = "My Name", locality = "New York", country = "US") } @Test @@ -146,7 +145,7 @@ class NodeConfigTest { + "\"detectPublicIp\":false," + "\"extraAdvertisedServiceIds\":[\"my.service\"]," + "\"h2port\":30001," - + "\"myLegalName\":\"C=US,L=New York,O=My Name,OU=Corda QA Department\"," + + "\"myLegalName\":\"C=US,L=New York,O=My Name\"," + "\"p2pAddress\":\"localhost:10001\"," + "\"rpcAddress\":\"localhost:40002\"," + "\"rpcUsers\":[" @@ -174,8 +173,8 @@ class NodeConfigTest { + "\"detectPublicIp\":false," + "\"extraAdvertisedServiceIds\":[\"my.service\"]," + "\"h2port\":30001," - + "\"myLegalName\":\"C=US,L=New York,O=My Name,OU=Corda QA Department\"," - + "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"C=CH,L=Zurich,O=Notary Service,OU=corda\"}," + + "\"myLegalName\":\"C=US,L=New York,O=My Name\"," + + "\"networkMapService\":{\"address\":\"localhost:12345\",\"legalName\":\"C=CH,L=Zurich,O=Notary Service\"}," + "\"p2pAddress\":\"localhost:10001\"," + "\"rpcAddress\":\"localhost:40002\"," + "\"rpcUsers\":[" @@ -253,7 +252,7 @@ class NodeConfigTest { } private fun createConfig( - legalName: X500Name = getX500Name(O = "Unknown", OU = "corda", L = "Nowhere", C = "GB"), + legalName: CordaX500Name = CordaX500Name(organisation = "Unknown", locality = "Nowhere", country = "GB"), p2pPort: Int = -1, rpcPort: Int = -1, webPort: Int = -1, diff --git a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt index 2aaec00fb9..f6c73aba2d 100644 --- a/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt +++ b/tools/demobench/src/test/kotlin/net/corda/demobench/model/NodeControllerTest.kt @@ -1,6 +1,6 @@ package net.corda.demobench.model -import net.corda.core.utilities.getX500Name +import net.corda.core.identity.CordaX500Name import net.corda.nodeapi.User import net.corda.testing.DUMMY_NOTARY import org.junit.Test @@ -12,8 +12,8 @@ class NodeControllerTest { private val baseDir: Path = Paths.get(".").toAbsolutePath() private val controller = NodeController({ _, _ -> }) - private val node1Name = "Node 1" - private val node2Name = "Node 2" + private val node1Name = "Organisation 1" + private val organisation2Name = "Organisation 2" @Test fun `test unique nodes after validate`() { @@ -28,9 +28,9 @@ class NodeControllerTest { val data = NodeData() data.legalName.value = node1Name - assertFalse(controller.keyExists("node1")) + assertFalse(controller.keyExists("organisation1")) controller.validate(data) - assertTrue(controller.keyExists("node1")) + assertTrue(controller.keyExists("organisation1")) } @Test @@ -38,13 +38,13 @@ class NodeControllerTest { val data = NodeData() data.legalName.value = node1Name - assertFalse(controller.nameExists("Node 1")) - assertFalse(controller.nameExists("Node1")) - assertFalse(controller.nameExists("node 1")) + assertFalse(controller.nameExists("Organisation 1")) + assertFalse(controller.nameExists("Organisation1")) + assertFalse(controller.nameExists("organisation 1")) controller.validate(data) - assertTrue(controller.nameExists("Node 1")) - assertTrue(controller.nameExists("Node1")) - assertTrue(controller.nameExists("node 1")) + assertTrue(controller.nameExists("Organisation 1")) + assertTrue(controller.nameExists("Organisation1")) + assertTrue(controller.nameExists("organisation 1")) } @Test @@ -60,36 +60,36 @@ class NodeControllerTest { @Test fun `test register unique nodes`() { - val config = createConfig(commonName = node2Name) + val config = createConfig(commonName = organisation2Name) assertTrue(controller.register(config)) assertFalse(controller.register(config)) } @Test fun `test unique key after register`() { - val config = createConfig(commonName = node2Name) + val config = createConfig(commonName = organisation2Name) - assertFalse(controller.keyExists("node2")) + assertFalse(controller.keyExists("organisation2")) controller.register(config) - assertTrue(controller.keyExists("node2")) + assertTrue(controller.keyExists("organisation2")) } @Test fun `test matching name after register`() { - val config = createConfig(commonName = node2Name) + val config = createConfig(commonName = organisation2Name) - assertFalse(controller.nameExists("Node 2")) - assertFalse(controller.nameExists("Node2")) - assertFalse(controller.nameExists("node 2")) + assertFalse(controller.nameExists("Organisation 2")) + assertFalse(controller.nameExists("Organisation2")) + assertFalse(controller.nameExists("organisation 2")) controller.register(config) - assertTrue(controller.nameExists("Node 2")) - assertTrue(controller.nameExists("Node2")) - assertTrue(controller.nameExists("node 2")) + assertTrue(controller.nameExists("Organisation 2")) + assertTrue(controller.nameExists("Organisation2")) + assertTrue(controller.nameExists("organisation 2")) } @Test fun `test register network map node`() { - val config = createConfig(commonName = "Node is Network Map") + val config = createConfig(commonName = "Organisation is Network Map") assertTrue(config.isNetworkMap()) assertFalse(controller.hasNetworkMap()) @@ -99,7 +99,7 @@ class NodeControllerTest { @Test fun `test register non-network-map node`() { - val config = createConfig(commonName = "Node is not Network Map") + val config = createConfig(commonName = "Organisation is not Network Map") config.networkMap = NetworkMapConfig(DUMMY_NOTARY.name, 10000) assertFalse(config.isNetworkMap()) @@ -174,10 +174,10 @@ class NodeControllerTest { users: List = listOf(user("guest")) ) = NodeConfig( baseDir, - legalName = getX500Name( - O = commonName, - L = "New York", - C = "US" + legalName = CordaX500Name( + organisation = commonName, + locality = "New York", + country = "US" ), p2pPort = p2pPort, rpcPort = rpcPort, diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt index d6e0b0575c..e4bf4a6578 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt @@ -6,6 +6,7 @@ import net.corda.client.mock.EventGenerator import net.corda.client.mock.Generator import net.corda.client.rpc.CordaRPCConnection import net.corda.core.contracts.Amount +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.concurrent.thenMatch import net.corda.core.messaging.CordaRPCOps @@ -15,7 +16,6 @@ import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceType import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow -import net.corda.core.utilities.getX500Name import net.corda.finance.GBP import net.corda.finance.USD import net.corda.finance.contracts.asset.Cash @@ -78,8 +78,8 @@ class ExplorerSimulation(val options: OptionSet) { val bob = startNode(providedName = BOB.name, rpcUsers = arrayListOf(user), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("cash"))), customOverrides = mapOf("nearestCity" to "Madrid")) - val ukBankName = getX500Name(O = "UK Bank Plc", L = "London", C = "GB") - val usaBankName = getX500Name(O = "USA Bank Corp", L = "New York", C = "USA") + val ukBankName = CordaX500Name(organisation = "UK Bank Plc", locality = "London", country = "GB") + val usaBankName = CordaX500Name(organisation = "USA Bank Corp", locality = "New York", country = "USA") val issuerGBP = startNode(providedName = ukBankName, rpcUsers = arrayListOf(manager), advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer.GBP"))), customOverrides = mapOf("nearestCity" to "London")) diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/PartyNameFormatter.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/PartyNameFormatter.kt index 2af31ad3ee..29ae6fe4c3 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/PartyNameFormatter.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/PartyNameFormatter.kt @@ -1,14 +1,15 @@ package net.corda.explorer.formatters +import net.corda.core.identity.CordaX500Name import net.corda.core.utilities.organisation import org.bouncycastle.asn1.x500.X500Name object PartyNameFormatter { - val short = object : Formatter { - override fun format(value: X500Name) = value.organisation + val short = object : Formatter { + override fun format(value: CordaX500Name) = value.organisation } - val full = object : Formatter { - override fun format(value: X500Name): String = value.toString() + val full = object : Formatter { + override fun format(value: CordaX500Name): String = value.toString() } } diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt index 4a94ec7555..1f5f1d3fa1 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/TransactionViewer.kt @@ -24,9 +24,9 @@ import net.corda.core.contracts.* import net.corda.core.crypto.SecureHash import net.corda.core.crypto.toStringShort import net.corda.core.identity.AbstractParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.node.NodeInfo -import net.corda.core.utilities.organisation import net.corda.core.utilities.toBase58String import net.corda.explorer.AmountDiff import net.corda.explorer.formatters.AmountFormatter @@ -40,7 +40,6 @@ import net.corda.explorer.model.ReportingCurrencyModel import net.corda.explorer.sign import net.corda.explorer.ui.setCustomCellFactory import net.corda.finance.contracts.asset.Cash -import org.bouncycastle.asn1.x500.X500Name import tornadofx.* import java.util.* @@ -200,7 +199,7 @@ class TransactionViewer : CordaView("Transactions") { }) } - private fun ObservableList>>.formatJoinPartyNames(separator: String = ",", formatter: Formatter): String { + private fun ObservableList>>.formatJoinPartyNames(separator: String = ",", formatter: Formatter): String { return flatten().map { it.value?.let { formatter.format(it.name) } }.filterNotNull().toSet().joinToString(separator) diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt index 86359414d8..2eb87db58a 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/GeneratedLedger.kt @@ -1,19 +1,18 @@ package net.corda.verifier -import net.corda.client.mock.* +import net.corda.client.mock.Generator import net.corda.core.contracts.* import net.corda.core.crypto.SecureHash import net.corda.core.crypto.entropyToKeyPair import net.corda.core.crypto.sha256 import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name import net.corda.core.identity.Party import net.corda.core.internal.AbstractAttachment import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.WireTransaction import net.corda.testing.contracts.DUMMY_PROGRAM_ID -import net.corda.core.utilities.getX500Name -import net.corda.testing.contracts.DummyContract import java.math.BigInteger import java.security.PublicKey import java.util.* @@ -208,7 +207,7 @@ fun commandGenerator(partiesToPickFrom: Collection): Generator = Generator.int().combine(publicKeyGenerator) { n, key -> - Party(getX500Name(O = "Party$n", L = "London", C = "GB"), key) + Party(CordaX500Name(organisation = "Party$n", locality = "London", country = "GB"), key) } fun pickOneOrMaybeNew(from: Collection, generator: Generator): Generator { diff --git a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt index d9aa442501..fd18c1abcf 100644 --- a/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt +++ b/verifier/src/integration-test/kotlin/net/corda/verifier/VerifierDriver.kt @@ -4,13 +4,12 @@ import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import net.corda.core.concurrent.CordaFuture import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.concurrent.* import net.corda.core.internal.div import net.corda.core.transactions.LedgerTransaction import net.corda.core.utilities.NetworkHostAndPort -import net.corda.core.utilities.getX500Name import net.corda.core.utilities.loggerFor -import net.corda.core.utilities.organisation import net.corda.node.services.config.configureDevKeyAndTrustStores import net.corda.nodeapi.ArtemisMessagingComponent.Companion.NODE_USER import net.corda.nodeapi.ArtemisTcpTransport @@ -31,7 +30,6 @@ 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 @@ -44,7 +42,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: X500Name): CordaFuture + fun startVerificationRequestor(name: CordaX500Name): CordaFuture /** Starts an out of process verifier connected to [address] */ fun startVerifier(address: NetworkHostAndPort): CordaFuture @@ -173,14 +171,14 @@ data class VerifierDriverDSL( } } - override fun startVerificationRequestor(name: X500Name): CordaFuture { + override fun startVerificationRequestor(name: CordaX500Name): CordaFuture { val hostAndPort = driverDSL.portAllocation.nextHostAndPort() return driverDSL.executorService.fork { startVerificationRequestorInternal(name, hostAndPort) } } - private fun startVerificationRequestorInternal(name: X500Name, hostAndPort: NetworkHostAndPort): VerificationRequestorHandle { + private fun startVerificationRequestorInternal(name: CordaX500Name, hostAndPort: NetworkHostAndPort): VerificationRequestorHandle { val baseDir = driverDSL.driverDirectory / name.organisation val sslConfig = object : NodeSSLConfiguration { override val baseDirectory = baseDir @@ -249,7 +247,7 @@ data class VerifierDriverDSL( val id = verifierCount.andIncrement val jdwpPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null val processFuture = driverDSL.executorService.fork { - val verifierName = getX500Name(O = "Verifier$id", L = "London", C = "GB") + val verifierName = CordaX500Name(organisation = "Verifier$id", locality = "London", country = "GB") val baseDirectory = driverDSL.driverDirectory / verifierName.organisation val config = createConfiguration(baseDirectory, address) val configFilename = "verifier.conf"