mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Store certificate and path with well known identity (#726)
* Construct standard flows using PartyAndCertificate, and add support for launching flows that are constructed with PartyAndCertificate or just Party. * Store PartyAndCertificate in network map service * Expand identity service to store certificates along with all identities.
This commit is contained in:
parent
08c91bd611
commit
34eb5a3b70
@ -3,45 +3,34 @@ package net.corda.core.flows
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
import net.corda.core.utilities.unwrap
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
/**
|
||||
* Very basic flow which exchanges transaction key and certificate paths between two parties in a transaction.
|
||||
* This is intended for use as a subflow of another flow.
|
||||
*/
|
||||
object TxKeyFlow {
|
||||
abstract class AbstractIdentityFlow<out T>(val otherSide: Party): FlowLogic<T>() {
|
||||
fun validateIdentity(untrustedIdentity: Pair<X509CertificateHolder, CertPath>): AnonymousIdentity {
|
||||
val (wellKnownCert, certPath) = untrustedIdentity
|
||||
val theirCert = certPath.certificates.last()
|
||||
// TODO: Don't trust self-signed certificates
|
||||
return if (theirCert is X509Certificate) {
|
||||
val certName = X500Name(theirCert.subjectDN.name)
|
||||
if (certName == otherSide.name) {
|
||||
val anonymousParty = AnonymousParty(theirCert.publicKey)
|
||||
serviceHub.identityService.registerPath(wellKnownCert, anonymousParty, certPath)
|
||||
AnonymousIdentity(certPath, X509CertificateHolder(theirCert.encoded), anonymousParty)
|
||||
} else {
|
||||
throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found $certName")
|
||||
}
|
||||
} else {
|
||||
throw IllegalStateException("Expected an X.509 certificate but received ${theirCert.javaClass.name}")
|
||||
}
|
||||
abstract class AbstractIdentityFlow<out T>(val otherSide: PartyAndCertificate, val revocationEnabled: Boolean): FlowLogic<T>() {
|
||||
fun validateIdentity(untrustedIdentity: AnonymousIdentity): AnonymousIdentity {
|
||||
val (certPath, theirCert, txIdentity) = untrustedIdentity
|
||||
if (theirCert.subject == otherSide.name) {
|
||||
serviceHub.identityService.registerAnonymousIdentity(txIdentity, otherSide, certPath)
|
||||
return AnonymousIdentity(certPath, theirCert, txIdentity)
|
||||
} else
|
||||
throw IllegalStateException("Expected certificate subject to be ${otherSide.name} but found ${theirCert.subject}")
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
@InitiatingFlow
|
||||
class Requester(otherSide: Party,
|
||||
val revocationEnabled: Boolean,
|
||||
override val progressTracker: ProgressTracker) : AbstractIdentityFlow<Map<Party, AnonymousIdentity>>(otherSide) {
|
||||
constructor(otherSide: Party, revocationEnabled: Boolean) : this(otherSide, revocationEnabled, tracker())
|
||||
|
||||
class Requester(otherSide: PartyAndCertificate,
|
||||
override val progressTracker: ProgressTracker) : AbstractIdentityFlow<Map<Party, AnonymousIdentity>>(otherSide, false) {
|
||||
constructor(otherSide: PartyAndCertificate) : this(otherSide, tracker())
|
||||
companion object {
|
||||
object AWAITING_KEY : ProgressTracker.Step("Awaiting key")
|
||||
|
||||
@ -52,9 +41,10 @@ object TxKeyFlow {
|
||||
override fun call(): Map<Party, AnonymousIdentity> {
|
||||
progressTracker.currentStep = AWAITING_KEY
|
||||
val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled)
|
||||
val theirIdentity = receive<Pair<X509CertificateHolder, CertPath>>(otherSide).unwrap { validateIdentity(it) }
|
||||
send(otherSide, myIdentityFragment)
|
||||
return mapOf(Pair(otherSide, AnonymousIdentity(myIdentityFragment)),
|
||||
val myIdentity = AnonymousIdentity(myIdentityFragment)
|
||||
val theirIdentity = receive<AnonymousIdentity>(otherSide).unwrap { validateIdentity(it) }
|
||||
send(otherSide, myIdentity)
|
||||
return mapOf(Pair(otherSide, myIdentity),
|
||||
Pair(serviceHub.myInfo.legalIdentity, theirIdentity))
|
||||
}
|
||||
}
|
||||
@ -64,7 +54,7 @@ object TxKeyFlow {
|
||||
* counterparty and as the result from the flow.
|
||||
*/
|
||||
@InitiatedBy(Requester::class)
|
||||
class Provider(otherSide: Party) : AbstractIdentityFlow<Unit>(otherSide) {
|
||||
class Provider(otherSide: PartyAndCertificate) : AbstractIdentityFlow<Map<Party, AnonymousIdentity>>(otherSide, false) {
|
||||
companion object {
|
||||
object SENDING_KEY : ProgressTracker.Step("Sending key")
|
||||
}
|
||||
@ -72,15 +62,19 @@ object TxKeyFlow {
|
||||
override val progressTracker: ProgressTracker = ProgressTracker(SENDING_KEY)
|
||||
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
override fun call(): Map<Party, AnonymousIdentity> {
|
||||
val revocationEnabled = false
|
||||
progressTracker.currentStep = SENDING_KEY
|
||||
val myIdentityFragment = serviceHub.keyManagementService.freshKeyAndCert(serviceHub.myInfo.legalIdentity, revocationEnabled)
|
||||
send(otherSide, myIdentityFragment)
|
||||
receive<Pair<X509CertificateHolder, CertPath>>(otherSide).unwrap { validateIdentity(it) }
|
||||
val myIdentity = AnonymousIdentity(myIdentityFragment)
|
||||
send(otherSide, myIdentity)
|
||||
val theirIdentity = receive<AnonymousIdentity>(otherSide).unwrap { validateIdentity(it) }
|
||||
return mapOf(Pair(otherSide, myIdentity),
|
||||
Pair(serviceHub.myInfo.legalIdentity, theirIdentity))
|
||||
}
|
||||
}
|
||||
|
||||
@CordaSerializable
|
||||
data class AnonymousIdentity(
|
||||
val certPath: CertPath,
|
||||
val certificate: X509CertificateHolder,
|
||||
|
@ -1,12 +1,9 @@
|
||||
package net.corda.core.identity
|
||||
|
||||
import net.corda.core.contracts.PartyAndReference
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import java.security.PublicKey
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
/**
|
||||
* A full party plus the X.509 certificate and path linking the party back to a trust root.
|
||||
|
@ -11,6 +11,7 @@ import net.corda.core.flows.FlowInitiator
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.NetworkMapCache
|
||||
import net.corda.core.node.services.StateMachineTransactionMapping
|
||||
@ -231,18 +232,18 @@ interface CordaRPCOps : RPCOps {
|
||||
/**
|
||||
* Returns the [Party] corresponding to the given key, if found.
|
||||
*/
|
||||
fun partyFromKey(key: PublicKey): Party?
|
||||
fun partyFromKey(key: PublicKey): PartyAndCertificate?
|
||||
|
||||
/**
|
||||
* Returns the [Party] with the given name as it's [Party.name]
|
||||
*/
|
||||
@Deprecated("Use partyFromX500Name instead")
|
||||
fun partyFromName(name: String): Party?
|
||||
fun partyFromName(name: String): PartyAndCertificate?
|
||||
|
||||
/**
|
||||
* Returns the [Party] with the X.500 principal as it's [Party.name]
|
||||
*/
|
||||
fun partyFromX500Name(x500Name: X500Name): Party?
|
||||
fun partyFromX500Name(x500Name: X500Name): PartyAndCertificate?
|
||||
|
||||
/** Enumerates the class names of the flows that this node knows about. */
|
||||
fun registeredFlows(): List<String>
|
||||
|
@ -1,24 +1,28 @@
|
||||
package net.corda.core.node
|
||||
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
|
||||
import java.security.cert.TrustAnchor
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
/**
|
||||
* Information for an advertised service including the service specific identity information.
|
||||
* The identity can be used in flows and is distinct from the Node's legalIdentity
|
||||
*/
|
||||
@CordaSerializable
|
||||
data class ServiceEntry(val info: ServiceInfo, val identity: Party)
|
||||
data class ServiceEntry(val info: ServiceInfo, val identity: PartyAndCertificate)
|
||||
|
||||
/**
|
||||
* Info about a network node that acts on behalf of some form of contract party.
|
||||
*/
|
||||
@CordaSerializable
|
||||
data class NodeInfo(val address: SingleMessageRecipient,
|
||||
val legalIdentity: Party,
|
||||
val legalIdentity: PartyAndCertificate,
|
||||
val platformVersion: Int,
|
||||
var advertisedServices: List<ServiceEntry> = emptyList(),
|
||||
val physicalLocation: PhysicalLocation? = null) {
|
||||
@ -26,6 +30,6 @@ data class NodeInfo(val address: SingleMessageRecipient,
|
||||
require(advertisedServices.none { it.identity == legalIdentity }) { "Service identities must be different from node legal identity" }
|
||||
}
|
||||
|
||||
val notaryIdentity: Party get() = advertisedServices.single { it.info.type.isNotary() }.identity
|
||||
val notaryIdentity: PartyAndCertificate get() = advertisedServices.single { it.info.type.isNotary() }.identity
|
||||
fun serviceIdentities(type: ServiceType): List<Party> = advertisedServices.filter { it.info.type.isSubTypeOf(type) }.map { it.identity }
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.corda.core.node
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
|
||||
/**
|
||||
* A service hub to be used by the [CordaPluginRegistry]
|
||||
@ -9,5 +10,5 @@ import net.corda.core.identity.Party
|
||||
interface PluginServiceHub : ServiceHub {
|
||||
@Deprecated("This is no longer used. Instead annotate the flows produced by your factory with @InitiatedBy and have " +
|
||||
"them point to the initiating flow class.", level = DeprecationLevel.ERROR)
|
||||
fun registerFlowInitiator(initiatingFlowClass: Class<out FlowLogic<*>>, serviceFlowFactory: (Party) -> FlowLogic<*>) = Unit
|
||||
fun registerFlowInitiator(initiatingFlowClass: Class<out FlowLogic<*>>, serviceFlowFactory: (PartyAndCertificate) -> FlowLogic<*>) = Unit
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
package net.corda.core.node.services
|
||||
|
||||
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 org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
import java.security.PublicKey
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
import java.security.cert.CertificateExpiredException
|
||||
import java.security.cert.CertificateNotYetValidException
|
||||
|
||||
/**
|
||||
* An identity service maintains an bidirectional map of [Party]s to their associated public keys and thus supports
|
||||
@ -17,21 +18,26 @@ import java.security.cert.X509Certificate
|
||||
* service would provide.
|
||||
*/
|
||||
interface IdentityService {
|
||||
fun registerIdentity(party: Party)
|
||||
/**
|
||||
* Verify and then store a well known identity.
|
||||
*
|
||||
* @param party a party representing a legal entity.
|
||||
* @throws IllegalArgumentException if the certificate path is invalid, or if there is already an existing
|
||||
* certificate chain for the anonymous party.
|
||||
*/
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
fun registerIdentity(party: PartyAndCertificate)
|
||||
|
||||
/**
|
||||
* Verify and then store the certificates proving that an anonymous party's key is owned by the given full
|
||||
* party.
|
||||
* Verify and then store an identity.
|
||||
*
|
||||
* @param trustedRoot trusted root certificate, typically the R3 master signing certificate.
|
||||
* @param anonymousParty an anonymised party belonging to the legal entity.
|
||||
* @param path certificate path from the trusted root to the anonymised party.
|
||||
* @throws IllegalArgumentException if the chain does not link the two parties, or if there is already an existing
|
||||
* certificate chain for the anonymous party. Anonymous parties must always resolve to a single owning party.
|
||||
* @param anonymousParty a party representing a legal entity in a transaction.
|
||||
* @param path certificate path from the trusted root to the party.
|
||||
* @throws IllegalArgumentException if the certificate path is invalid, or if there is already an existing
|
||||
* certificate chain for the anonymous party.
|
||||
*/
|
||||
// TODO: Move this into internal identity service once available
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath)
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath)
|
||||
|
||||
/**
|
||||
* Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with
|
||||
@ -52,10 +58,10 @@ interface IdentityService {
|
||||
// indefinitely. It may be that in the long term we need to drop or archive very old Party information for space,
|
||||
// but for now this is not supported.
|
||||
|
||||
fun partyFromKey(key: PublicKey): Party?
|
||||
fun partyFromKey(key: PublicKey): PartyAndCertificate?
|
||||
@Deprecated("Use partyFromX500Name")
|
||||
fun partyFromName(name: String): Party?
|
||||
fun partyFromX500Name(principal: X500Name): Party?
|
||||
fun partyFromName(name: String): PartyAndCertificate?
|
||||
fun partyFromX500Name(principal: X500Name): PartyAndCertificate?
|
||||
|
||||
/**
|
||||
* Resolve the well known identity of a party. If the party passed in is already a well known identity
|
||||
@ -63,7 +69,7 @@ interface IdentityService {
|
||||
*
|
||||
* @return the well known identity, or null if unknown.
|
||||
*/
|
||||
fun partyFromAnonymous(party: AbstractParty): Party?
|
||||
fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate?
|
||||
|
||||
/**
|
||||
* Resolve the well known identity of a party. If the party passed in is already a well known identity
|
||||
|
@ -10,6 +10,7 @@ import net.corda.core.crypto.keys
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.vault.PageSpecification
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.core.node.services.vault.Sort
|
||||
@ -20,6 +21,7 @@ import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
import rx.Observable
|
||||
import java.io.InputStream
|
||||
import java.security.PublicKey
|
||||
@ -399,7 +401,7 @@ interface KeyManagementService {
|
||||
* @return X.509 certificate and path to the trust root.
|
||||
*/
|
||||
@Suspendable
|
||||
fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath>
|
||||
fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath>
|
||||
|
||||
/** Using the provided signing [PublicKey] internally looks up the matching [PrivateKey] and signs the data.
|
||||
* @param bytes The data to sign over using the chosen key.
|
||||
|
@ -10,6 +10,7 @@ import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
@ -119,7 +120,7 @@ abstract class AbstractStateReplacementFlow {
|
||||
|
||||
// Type parameter should ideally be Unit but that prevents Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964).
|
||||
// We use Void? instead of Unit? as that's what you'd use in Java.
|
||||
abstract class Acceptor<in T>(val otherSide: Party,
|
||||
abstract class Acceptor<in T>(val otherSide: PartyAndCertificate,
|
||||
override val progressTracker: ProgressTracker = tracker()) : FlowLogic<Void?>() {
|
||||
companion object {
|
||||
object VERIFYING : ProgressTracker.Step("Verifying state replacement proposal")
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.crypto.toBase58String
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
@ -173,7 +174,7 @@ class CollectSignaturesFlow(val partiallySignedTx: SignedTransaction,
|
||||
*
|
||||
* @param otherParty The counter-party which is providing you a transaction to sign.
|
||||
*/
|
||||
abstract class SignTransactionFlow(val otherParty: Party,
|
||||
abstract class SignTransactionFlow(val otherParty: PartyAndCertificate,
|
||||
override val progressTracker: ProgressTracker = tracker()) : FlowLogic<SignedTransaction>() {
|
||||
|
||||
companion object {
|
||||
|
@ -5,7 +5,7 @@ import net.corda.core.contracts.Attachment
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.SerializationToken
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SerializeAsTokenContext
|
||||
@ -16,7 +16,7 @@ import net.corda.core.serialization.SerializeAsTokenContext
|
||||
*/
|
||||
@InitiatingFlow
|
||||
class FetchAttachmentsFlow(requests: Set<SecureHash>,
|
||||
otherSide: Party) : FetchDataFlow<Attachment, ByteArray>(requests, otherSide) {
|
||||
otherSide: PartyAndCertificate) : FetchDataFlow<Attachment, ByteArray>(requests, otherSide) {
|
||||
|
||||
override fun load(txid: SecureHash): Attachment? = serviceHub.storageService.attachments.openAttachment(txid)
|
||||
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
import net.corda.core.utilities.unwrap
|
||||
@ -31,7 +32,7 @@ import java.util.*
|
||||
*/
|
||||
abstract class FetchDataFlow<T : NamedByHash, in W : Any>(
|
||||
protected val requests: Set<SecureHash>,
|
||||
protected val otherSide: Party) : FlowLogic<FetchDataFlow.Result<T>>() {
|
||||
protected val otherSide: PartyAndCertificate) : FlowLogic<FetchDataFlow.Result<T>>() {
|
||||
|
||||
@CordaSerializable
|
||||
class DownloadedVsRequestedDataMismatch(val requested: SecureHash, val got: SecureHash) : IllegalArgumentException()
|
||||
|
@ -2,7 +2,7 @@ package net.corda.flows
|
||||
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
|
||||
/**
|
||||
@ -14,7 +14,7 @@ import net.corda.core.transactions.SignedTransaction
|
||||
* the database, because it's up to the caller to actually verify the transactions are valid.
|
||||
*/
|
||||
@InitiatingFlow
|
||||
class FetchTransactionsFlow(requests: Set<SecureHash>, otherSide: Party) :
|
||||
class FetchTransactionsFlow(requests: Set<SecureHash>, otherSide: PartyAndCertificate) :
|
||||
FetchDataFlow<SignedTransaction, SignedTransaction>(requests, otherSide) {
|
||||
|
||||
override fun load(txid: SecureHash): SignedTransaction? {
|
||||
|
@ -4,6 +4,7 @@ import net.corda.core.contracts.*
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
@ -21,7 +22,7 @@ import java.security.PublicKey
|
||||
@InitiatingFlow
|
||||
class NotaryChangeFlow<out T : ContractState>(
|
||||
originalState: StateAndRef<T>,
|
||||
newNotary: Party,
|
||||
newNotary: PartyAndCertificate,
|
||||
progressTracker: ProgressTracker = tracker())
|
||||
: AbstractStateReplacementFlow.Instigator<T, T, Party>(originalState, newNotary, progressTracker) {
|
||||
|
||||
|
@ -11,6 +11,7 @@ import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
import net.corda.core.node.services.UniquenessException
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
@ -96,7 +97,7 @@ object NotaryFlow {
|
||||
* Additional transaction validation logic can be added when implementing [receiveAndVerifyTx].
|
||||
*/
|
||||
// See AbstractStateReplacementFlow.Acceptor for why it's Void?
|
||||
abstract class Service(val otherSide: Party,
|
||||
abstract class Service(val otherSide: PartyAndCertificate,
|
||||
val timeWindowChecker: TimeWindowChecker,
|
||||
val uniquenessProvider: UniquenessProvider) : FlowLogic<Void?>() {
|
||||
@Suspendable
|
||||
|
@ -5,7 +5,7 @@ import net.corda.core.checkedAdd
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -30,7 +30,7 @@ import java.util.*
|
||||
* The flow returns a list of verified [LedgerTransaction] objects, in a depth-first order.
|
||||
*/
|
||||
class ResolveTransactionsFlow(private val txHashes: Set<SecureHash>,
|
||||
private val otherSide: Party) : FlowLogic<List<LedgerTransaction>>() {
|
||||
private val otherSide: PartyAndCertificate) : FlowLogic<List<LedgerTransaction>>() {
|
||||
|
||||
companion object {
|
||||
private fun dependencyIDs(wtx: WireTransaction) = wtx.inputs.map { it.txhash }.toSet()
|
||||
@ -82,14 +82,14 @@ class ResolveTransactionsFlow(private val txHashes: Set<SecureHash>,
|
||||
/**
|
||||
* Resolve the full history of a transaction and verify it with its dependencies.
|
||||
*/
|
||||
constructor(stx: SignedTransaction, otherSide: Party) : this(stx.tx, otherSide) {
|
||||
constructor(stx: SignedTransaction, otherSide: PartyAndCertificate) : this(stx.tx, otherSide) {
|
||||
this.stx = stx
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the full history of a transaction and verify it with its dependencies.
|
||||
*/
|
||||
constructor(wtx: WireTransaction, otherSide: Party) : this(dependencyIDs(wtx), otherSide) {
|
||||
constructor(wtx: WireTransaction, otherSide: PartyAndCertificate) : this(dependencyIDs(wtx), otherSide) {
|
||||
this.wtx = wtx
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.seconds
|
||||
@ -45,7 +46,7 @@ object TwoPartyDealFlow {
|
||||
|
||||
abstract val payload: Any
|
||||
abstract val notaryNode: NodeInfo
|
||||
abstract val otherParty: Party
|
||||
abstract val otherParty: PartyAndCertificate
|
||||
abstract val myKey: PublicKey
|
||||
|
||||
@Suspendable override fun call(): SignedTransaction {
|
||||
@ -149,7 +150,7 @@ object TwoPartyDealFlow {
|
||||
/**
|
||||
* One side of the flow for inserting a pre-agreed deal.
|
||||
*/
|
||||
open class Instigator(override val otherParty: Party,
|
||||
open class Instigator(override val otherParty: PartyAndCertificate,
|
||||
override val payload: AutoOffer,
|
||||
override val myKey: PublicKey,
|
||||
override val progressTracker: ProgressTracker = Primary.tracker()) : Primary() {
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.contracts.requireThat
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.flows.CollectSignaturesFlow
|
||||
@ -54,7 +55,7 @@ class CollectSignaturesFlowTests {
|
||||
// "collectSignaturesFlow" and "SignTransactionFlow" can be used in practise.
|
||||
object TestFlow {
|
||||
@InitiatingFlow
|
||||
class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: Party) : FlowLogic<SignedTransaction>() {
|
||||
class Initiator(val state: DummyContract.MultiOwnerState, val otherParty: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
send(otherParty, state)
|
||||
@ -114,7 +115,7 @@ class CollectSignaturesFlowTests {
|
||||
}
|
||||
|
||||
@InitiatedBy(TestFlowTwo.Initiator::class)
|
||||
class Responder(val otherParty: Party) : FlowLogic<SignedTransaction>() {
|
||||
class Responder(val otherParty: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable override fun call(): SignedTransaction {
|
||||
val flow = object : SignTransactionFlow(otherParty) {
|
||||
@Suspendable override fun checkTransaction(stx: SignedTransaction) = requireThat {
|
||||
|
@ -3,6 +3,7 @@ package net.corda.core.flows
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.BOB
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
@ -26,12 +27,11 @@ class TxKeyFlowTests {
|
||||
net = MockNetwork(false, true)
|
||||
|
||||
// Set up values we'll need
|
||||
val revocationEnabled = false
|
||||
val notaryNode = net.createNotaryNode(null, DUMMY_NOTARY.name)
|
||||
val aliceNode = net.createPartyNode(notaryNode.info.address, ALICE.name)
|
||||
val bobNode = net.createPartyNode(notaryNode.info.address, BOB.name)
|
||||
val alice: Party = aliceNode.services.myInfo.legalIdentity
|
||||
val bob: Party = bobNode.services.myInfo.legalIdentity
|
||||
val alice: PartyAndCertificate = aliceNode.services.myInfo.legalIdentity
|
||||
val bob: PartyAndCertificate = bobNode.services.myInfo.legalIdentity
|
||||
aliceNode.services.identityService.registerIdentity(bob)
|
||||
aliceNode.services.identityService.registerIdentity(notaryNode.info.legalIdentity)
|
||||
bobNode.services.identityService.registerIdentity(alice)
|
||||
@ -39,7 +39,7 @@ class TxKeyFlowTests {
|
||||
|
||||
// Run the flows
|
||||
bobNode.registerInitiatedFlow(TxKeyFlow.Provider::class.java)
|
||||
val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob, revocationEnabled))
|
||||
val requesterFlow = aliceNode.services.startFlow(TxKeyFlow.Requester(bob))
|
||||
|
||||
// Get the results
|
||||
val actual: Map<Party, TxKeyFlow.AnonymousIdentity> = requesterFlow.resultFuture.getOrThrow()
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.RPCOps
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
@ -139,7 +140,7 @@ class AttachmentSerializationTest {
|
||||
|
||||
private fun launchFlow(clientLogic: ClientLogic, rounds: Int) {
|
||||
server.registerFlowFactory(ClientLogic::class.java, object : InitiatedFlowFactory<ServerLogic> {
|
||||
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): ServerLogic {
|
||||
override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): ServerLogic {
|
||||
return ServerLogic(otherParty)
|
||||
}
|
||||
}, ServerLogic::class.java, track = false)
|
||||
|
@ -43,9 +43,18 @@ UNRELEASED
|
||||
* There is a new ``AbstractParty`` superclass to ``Party``, which contains just the public key. This now replaces
|
||||
use of ``Party`` and ``PublicKey`` in state objects, and allows use of full or anonymised parties depending on
|
||||
use-case.
|
||||
* A new ``PartyAndCertificate`` class has been added which contains an X.509 certificate and certificate path back
|
||||
to a network trust root. This is widely used in place of ``Party`` inside Corda, with the exception of a few cases
|
||||
where proof of identity is not required.
|
||||
* Names of parties are now stored as a ``X500Name`` rather than a ``String``, to correctly enforce basic structure of the
|
||||
name. As a result all node legal names must now be structured as X.500 distinguished names.
|
||||
|
||||
* Flows can now accept ``PartyAndCertificate`` instead of ``Party`` in their constructor, which should be the default for
|
||||
new flows. The sample flows have been updated to use ``PartyAndCertificate`` to illustrate this.
|
||||
|
||||
* The identity management service takes an optional network trust root which it will validate certificate paths to, if
|
||||
provided. A later release will make this a required parameter.
|
||||
|
||||
* There are major changes to transaction signing in flows:
|
||||
|
||||
* You should use the new ``CollectSignaturesFlow`` and corresponding ``SignTransactionFlow`` which handle most
|
||||
|
@ -12,6 +12,8 @@ import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.PluginServiceHub
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -24,8 +26,8 @@ import java.util.*
|
||||
@CordaSerializable
|
||||
private data class FxRequest(val tradeId: String,
|
||||
val amount: Amount<Issued<Currency>>,
|
||||
val owner: Party,
|
||||
val counterparty: Party,
|
||||
val owner: PartyAndCertificate,
|
||||
val counterparty: PartyAndCertificate,
|
||||
val notary: Party? = null)
|
||||
|
||||
@CordaSerializable
|
||||
@ -101,8 +103,8 @@ private fun prepareOurInputsAndOutputs(serviceHub: ServiceHub, request: FxReques
|
||||
class ForeignExchangeFlow(val tradeId: String,
|
||||
val baseCurrencyAmount: Amount<Issued<Currency>>,
|
||||
val quoteCurrencyAmount: Amount<Issued<Currency>>,
|
||||
val baseCurrencyBuyer: Party,
|
||||
val baseCurrencySeller: Party) : FlowLogic<SecureHash>() {
|
||||
val baseCurrencyBuyer: PartyAndCertificate,
|
||||
val baseCurrencySeller: PartyAndCertificate) : FlowLogic<SecureHash>() {
|
||||
@Suspendable
|
||||
override fun call(): SecureHash {
|
||||
// Select correct sides of the Fx exchange to query for.
|
||||
@ -206,7 +208,7 @@ class ForeignExchangeFlow(val tradeId: String,
|
||||
}
|
||||
|
||||
@InitiatedBy(ForeignExchangeFlow::class)
|
||||
class ForeignExchangeRemoteFlow(val source: Party) : FlowLogic<Unit>() {
|
||||
class ForeignExchangeRemoteFlow(val source: PartyAndCertificate) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
// Initial receive from remote party
|
||||
|
@ -7,7 +7,7 @@ import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.seconds
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -61,7 +61,7 @@ object TwoPartyTradeFlow {
|
||||
data class SignaturesFromSeller(val sellerSig: DigitalSignature.WithKey,
|
||||
val notarySig: DigitalSignature.WithKey)
|
||||
|
||||
open class Seller(val otherParty: Party,
|
||||
open class Seller(val otherParty: PartyAndCertificate,
|
||||
val notaryNode: NodeInfo,
|
||||
val assetToSell: StateAndRef<OwnableState>,
|
||||
val price: Amount<Currency>,
|
||||
@ -141,8 +141,8 @@ object TwoPartyTradeFlow {
|
||||
}
|
||||
}
|
||||
|
||||
open class Buyer(val otherParty: Party,
|
||||
val notary: Party,
|
||||
open class Buyer(val otherParty: PartyAndCertificate,
|
||||
val notary: PartyAndCertificate,
|
||||
val acceptablePrice: Amount<Currency>,
|
||||
val typeToBuy: Class<out OwnableState>) : FlowLogic<SignedTransaction>() {
|
||||
// DOCSTART 2
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.flows;
|
||||
|
||||
import net.corda.core.identity.Party;
|
||||
import net.corda.core.identity.PartyAndCertificate;
|
||||
import net.corda.core.utilities.*;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
@ -9,7 +10,7 @@ public class AbstractStateReplacementFlowTest {
|
||||
|
||||
// Acceptor used to have a type parameter of Unit which prevented Java code from subclassing it (https://youtrack.jetbrains.com/issue/KT-15964).
|
||||
private static class TestAcceptorCanBeInheritedInJava extends AbstractStateReplacementFlow.Acceptor {
|
||||
public TestAcceptorCanBeInheritedInJava(@NotNull Party otherSide, @NotNull ProgressTracker progressTracker) {
|
||||
public TestAcceptorCanBeInheritedInJava(@NotNull PartyAndCertificate otherSide, @NotNull ProgressTracker progressTracker) {
|
||||
super(otherSide, progressTracker);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ 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.bouncycastle.cert.X509CertificateHolder
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.TimeoutException
|
||||
@ -56,17 +57,19 @@ class P2PSecurityTest : NodeBasedTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun startSimpleNode(legalName: X500Name): SimpleNode {
|
||||
private fun startSimpleNode(legalName: X500Name,
|
||||
trustRoot: X509CertificateHolder? = null): SimpleNode {
|
||||
val config = TestNodeConfiguration(
|
||||
baseDirectory = baseDirectory(legalName),
|
||||
myLegalName = legalName,
|
||||
networkMapService = NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name))
|
||||
config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name
|
||||
return SimpleNode(config).apply { start() }
|
||||
return SimpleNode(config, trustRoot = trustRoot).apply { start() }
|
||||
}
|
||||
|
||||
private fun SimpleNode.registerWithNetworkMap(registrationName: X500Name): ListenableFuture<NetworkMapService.RegistrationResponse> {
|
||||
val nodeInfo = NodeInfo(net.myAddress, getTestPartyAndCertificate(registrationName, identity.public), MOCK_VERSION_INFO.platformVersion)
|
||||
val legalIdentity = getTestPartyAndCertificate(registrationName, identity.public)
|
||||
val nodeInfo = NodeInfo(net.myAddress, legalIdentity, MOCK_VERSION_INFO.platformVersion)
|
||||
val registration = NodeRegistration(nodeInfo, System.currentTimeMillis(), AddOrRemove.ADD, Instant.MAX)
|
||||
val request = RegistrationRequest(registration.toWire(keyService, identity.public), net.myAddress)
|
||||
return net.sendRequest<NetworkMapService.RegistrationResponse>(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress)
|
||||
|
@ -14,6 +14,9 @@ import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.crypto.appendToCommonName
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.ShutdownHook
|
||||
import net.corda.core.internal.addShutdownHook
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
@ -28,8 +31,6 @@ import net.corda.nodeapi.ArtemisMessagingComponent
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.nodeapi.config.SSLConfiguration
|
||||
import net.corda.nodeapi.config.parseAs
|
||||
import net.corda.core.internal.ShutdownHook
|
||||
import net.corda.core.internal.addShutdownHook
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
@ -96,7 +97,7 @@ interface DriverDSLExposedInterface : CordformContext {
|
||||
clusterSize: Int = 3,
|
||||
type: ServiceType = RaftValidatingNotaryService.type,
|
||||
verifierType: VerifierType = VerifierType.InMemory,
|
||||
rpcUsers: List<User> = emptyList()): Future<Pair<Party, List<NodeHandle>>>
|
||||
rpcUsers: List<User> = emptyList()): Future<Pair<PartyAndCertificate, List<NodeHandle>>>
|
||||
|
||||
/**
|
||||
* Starts a web server for a node
|
||||
@ -553,7 +554,7 @@ class DriverDSL(
|
||||
type: ServiceType,
|
||||
verifierType: VerifierType,
|
||||
rpcUsers: List<User>
|
||||
): ListenableFuture<Pair<Party, List<NodeHandle>>> {
|
||||
): ListenableFuture<Pair<PartyAndCertificate, List<NodeHandle>>> {
|
||||
val nodeNames = (0 until clusterSize).map { DUMMY_NOTARY.name.appendToCommonName(" $it") }
|
||||
val paths = nodeNames.map { baseDirectory(it) }
|
||||
ServiceIdentityGenerator.generateToDisk(paths, DUMMY_CA, type.id, notaryName)
|
||||
|
@ -71,6 +71,7 @@ import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyStoreException
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Clock
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@ -346,7 +347,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
}
|
||||
|
||||
private fun <F : FlowLogic<*>> registerInitiatedFlowInternal(initiatedFlow: Class<F>, track: Boolean): Observable<F> {
|
||||
val ctor = initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true }
|
||||
val ctor = try {
|
||||
initiatedFlow.getDeclaredConstructor(PartyAndCertificate::class.java).apply { isAccessible = true }
|
||||
} catch(ex: NoSuchMethodException) {
|
||||
// Fall back to a constructor that takes in a Party
|
||||
// TODO: Consider removing for 1.0 release, as flows should generally take the more detailed class
|
||||
initiatedFlow.getDeclaredConstructor(Party::class.java).apply { isAccessible = true }
|
||||
}
|
||||
val initiatingFlow = initiatedFlow.requireAnnotation<InitiatedBy>().value.java
|
||||
val (version, classWithAnnotation) = initiatingFlow.flowVersionAndInitiatingClass
|
||||
require(classWithAnnotation == initiatingFlow) {
|
||||
@ -394,7 +401,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
* @suppress
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun installCoreFlow(clientFlowClass: KClass<out FlowLogic<*>>, flowFactory: (Party, Int) -> FlowLogic<*>) {
|
||||
fun installCoreFlow(clientFlowClass: KClass<out FlowLogic<*>>, flowFactory: (PartyAndCertificate, Int) -> FlowLogic<*>) {
|
||||
require(clientFlowClass.java.flowVersionAndInitiatingClass.first == 1) {
|
||||
"${InitiatingFlow::class.java.name}.version not applicable for core flows; their version is the node's platform version"
|
||||
}
|
||||
@ -656,7 +663,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
protected abstract fun makeUniquenessProvider(type: ServiceType): UniquenessProvider
|
||||
|
||||
protected open fun makeIdentityService(): IdentityService {
|
||||
val service = InMemoryIdentityService()
|
||||
val keyStore = KeyStoreUtilities.loadKeyStore(configuration.trustStoreFile, configuration.trustStorePassword)
|
||||
val trustRoot = keyStore.getCertificate(X509Utilities.CORDA_ROOT_CA) as? X509Certificate
|
||||
val service = InMemoryIdentityService(trustRoot = trustRoot)
|
||||
service.registerIdentity(info.legalIdentity)
|
||||
services.networkMapCache.partyNodes.forEach { service.registerIdentity(it.legalIdentity) }
|
||||
netMapCache.changed.subscribe { mapChange ->
|
||||
|
@ -2,19 +2,20 @@ package net.corda.node.internal
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.node.services.statemachine.SessionInit
|
||||
|
||||
interface InitiatedFlowFactory<out F : FlowLogic<*>> {
|
||||
fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F
|
||||
fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F
|
||||
|
||||
data class Core<out F : FlowLogic<*>>(val factory: (Party, Int) -> F) : InitiatedFlowFactory<F> {
|
||||
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F {
|
||||
data class Core<out F : FlowLogic<*>>(val factory: (PartyAndCertificate, Int) -> F) : InitiatedFlowFactory<F> {
|
||||
override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F {
|
||||
return factory(otherParty, platformVersion)
|
||||
}
|
||||
}
|
||||
|
||||
data class CorDapp<out F : FlowLogic<*>>(val version: Int, val factory: (Party) -> F) : InitiatedFlowFactory<F> {
|
||||
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): F {
|
||||
override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): F {
|
||||
// TODO Add support for multiple versions of the same flow when CorDapps are loaded in separate class loaders
|
||||
if (sessionInit.flowVerison == version) return factory(otherParty)
|
||||
throw SessionRejectException(
|
||||
|
@ -5,10 +5,11 @@ import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.TransactionType
|
||||
import net.corda.core.contracts.UpgradedContract
|
||||
import net.corda.core.contracts.requireThat
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.FlowException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.flows.*
|
||||
@ -25,20 +26,20 @@ import net.corda.flows.*
|
||||
*
|
||||
* Additionally, because nodes do not store invalid transactions, requesting such a transaction will always yield null.
|
||||
*/
|
||||
class FetchTransactionsHandler(otherParty: Party) : FetchDataHandler<SignedTransaction>(otherParty) {
|
||||
class FetchTransactionsHandler(otherParty: PartyAndCertificate) : FetchDataHandler<SignedTransaction>(otherParty) {
|
||||
override fun getData(id: SecureHash): SignedTransaction? {
|
||||
return serviceHub.storageService.validatedTransactions.getTransaction(id)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use Artemis message streaming support here, called "large messages". This avoids the need to buffer.
|
||||
class FetchAttachmentsHandler(otherParty: Party) : FetchDataHandler<ByteArray>(otherParty) {
|
||||
class FetchAttachmentsHandler(otherParty: PartyAndCertificate) : FetchDataHandler<ByteArray>(otherParty) {
|
||||
override fun getData(id: SecureHash): ByteArray? {
|
||||
return serviceHub.storageService.attachments.openAttachment(id)?.open()?.readBytes()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class FetchDataHandler<out T>(val otherParty: Party) : FlowLogic<Unit>() {
|
||||
abstract class FetchDataHandler<out T>(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
@Throws(FetchDataFlow.HashNotFound::class)
|
||||
override fun call() {
|
||||
@ -59,7 +60,7 @@ abstract class FetchDataHandler<out T>(val otherParty: Party) : FlowLogic<Unit>(
|
||||
// includes us in any outside that list. Potentially just if it includes any outside that list at all.
|
||||
// TODO: Do we want to be able to reject specific transactions on more complex rules, for example reject incoming
|
||||
// cash without from unknown parties?
|
||||
class NotifyTransactionHandler(val otherParty: Party) : FlowLogic<Unit>() {
|
||||
class NotifyTransactionHandler(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
val request = receive<BroadcastTransactionFlow.NotifyTxRequest>(otherParty).unwrap { it }
|
||||
@ -68,7 +69,7 @@ class NotifyTransactionHandler(val otherParty: Party) : FlowLogic<Unit>() {
|
||||
}
|
||||
}
|
||||
|
||||
class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor<Party>(otherSide) {
|
||||
class NotaryChangeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor<PartyAndCertificate>(otherSide) {
|
||||
/**
|
||||
* Check the notary change proposal.
|
||||
*
|
||||
@ -76,7 +77,7 @@ class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Accep
|
||||
* and is also in a geographically convenient location we can just automatically approve the change.
|
||||
* TODO: In more difficult cases this should call for human attention to manually verify and approve the proposal
|
||||
*/
|
||||
override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<Party>): Unit {
|
||||
override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<PartyAndCertificate>): Unit {
|
||||
val state = proposal.stateRef
|
||||
val proposedTx = proposal.stx.tx
|
||||
|
||||
@ -101,7 +102,7 @@ class NotaryChangeHandler(otherSide: Party) : AbstractStateReplacementFlow.Accep
|
||||
}
|
||||
}
|
||||
|
||||
class ContractUpgradeHandler(otherSide: Party) : AbstractStateReplacementFlow.Acceptor<Class<out UpgradedContract<ContractState, *>>>(otherSide) {
|
||||
class ContractUpgradeHandler(otherSide: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor<Class<out UpgradedContract<ContractState, *>>>(otherSide) {
|
||||
@Suspendable
|
||||
@Throws(StateReplacementException::class)
|
||||
override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<Class<out UpgradedContract<ContractState, *>>>) {
|
||||
|
@ -2,10 +2,12 @@ package net.corda.node.services.identity
|
||||
|
||||
import net.corda.core.contracts.PartyAndReference
|
||||
import net.corda.core.contracts.requireThat
|
||||
import net.corda.core.crypto.subject
|
||||
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.node.services.IdentityService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.loggerFor
|
||||
@ -27,15 +29,20 @@ import javax.annotation.concurrent.ThreadSafe
|
||||
* @param certPaths initial set of certificate paths for the service, typically only used for unit tests.
|
||||
*/
|
||||
@ThreadSafe
|
||||
class InMemoryIdentityService(identities: Iterable<Party> = emptySet(),
|
||||
certPaths: Map<AnonymousParty, CertPath> = emptyMap()) : SingletonSerializeAsToken(), IdentityService {
|
||||
class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptySet(),
|
||||
certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
|
||||
val trustRoot: X509Certificate?) : SingletonSerializeAsToken(), IdentityService {
|
||||
constructor(identities: Iterable<PartyAndCertificate> = emptySet(),
|
||||
certPaths: Map<AnonymousParty, CertPath> = emptyMap(),
|
||||
trustRoot: X509CertificateHolder?) : this(identities, certPaths, trustRoot?.let { JcaX509CertificateConverter().getCertificate(it) })
|
||||
companion object {
|
||||
private val log = loggerFor<InMemoryIdentityService>()
|
||||
}
|
||||
|
||||
private val keyToParties = ConcurrentHashMap<PublicKey, Party>()
|
||||
private val principalToParties = ConcurrentHashMap<X500Name, Party>()
|
||||
private val partyToPath = ConcurrentHashMap<AnonymousParty, CertPath>()
|
||||
private val trustAnchor: TrustAnchor? = trustRoot?.let { cert -> TrustAnchor(cert, null) }
|
||||
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
||||
private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
|
||||
private val partyToPath = ConcurrentHashMap<AbstractParty, CertPath>()
|
||||
|
||||
init {
|
||||
keyToParties.putAll(identities.associateBy { it.owningKey } )
|
||||
@ -43,8 +50,29 @@ class InMemoryIdentityService(identities: Iterable<Party> = emptySet(),
|
||||
partyToPath.putAll(certPaths)
|
||||
}
|
||||
|
||||
override fun registerIdentity(party: Party) {
|
||||
// TODO: Check the validation logic
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
override fun registerIdentity(party: PartyAndCertificate) {
|
||||
require(party.certPath.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" }
|
||||
// Validate the chain first, before we do anything clever with it
|
||||
val validatorParameters = if (trustAnchor != null) {
|
||||
PKIXParameters(setOf(trustAnchor))
|
||||
} else {
|
||||
// TODO: We should always require a full chain back to a trust anchor, but until we have a network
|
||||
// trust anchor everywhere, this will have to do.
|
||||
val converter = JcaX509CertificateConverter()
|
||||
PKIXParameters(setOf(TrustAnchor(converter.getCertificate(party.certificate), null)))
|
||||
}
|
||||
val validator = CertPathValidator.getInstance("PKIX")
|
||||
validatorParameters.isRevocationEnabled = false
|
||||
// TODO: val result = validator.validate(party.certPath, validatorParameters) as PKIXCertPathValidatorResult
|
||||
// require(trustAnchor == null || result.trustAnchor == trustAnchor)
|
||||
// require(result.publicKey == party.owningKey) { "Certificate path validation must end at transaction key ${anonymousParty.owningKey.toStringShort()}, found ${result.publicKey.toStringShort()}" }
|
||||
|
||||
log.trace { "Registering identity $party" }
|
||||
require(Arrays.equals(party.certificate.subjectPublicKeyInfo.encoded, party.owningKey.encoded)) { "Party certificate must end with party's public key" }
|
||||
|
||||
partyToPath[party] = party.certPath
|
||||
keyToParties[party.owningKey] = party
|
||||
principalToParties[party.name] = party
|
||||
}
|
||||
@ -52,12 +80,12 @@ class InMemoryIdentityService(identities: Iterable<Party> = emptySet(),
|
||||
// We give the caller a copy of the data set to avoid any locking problems
|
||||
override fun getAllIdentities(): Iterable<Party> = ArrayList(keyToParties.values)
|
||||
|
||||
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]
|
||||
override fun partyFromKey(key: PublicKey): PartyAndCertificate? = keyToParties[key]
|
||||
@Deprecated("Use partyFromX500Name")
|
||||
override fun partyFromName(name: String): Party? = principalToParties[X500Name(name)]
|
||||
override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]
|
||||
override fun partyFromAnonymous(party: AbstractParty): Party? {
|
||||
return if (party is Party) {
|
||||
override fun partyFromName(name: String): PartyAndCertificate? = principalToParties[X500Name(name)]
|
||||
override fun partyFromX500Name(principal: X500Name): PartyAndCertificate? = principalToParties[principal]
|
||||
override fun partyFromAnonymous(party: AbstractParty): PartyAndCertificate? {
|
||||
return if (party is PartyAndCertificate) {
|
||||
party
|
||||
} else {
|
||||
partyFromKey(party.owningKey)
|
||||
@ -84,20 +112,29 @@ class InMemoryIdentityService(identities: Iterable<Party> = emptySet(),
|
||||
override fun pathForAnonymous(anonymousParty: AnonymousParty): CertPath? = partyToPath[anonymousParty]
|
||||
|
||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||
override fun registerPath(trustedRoot: X509CertificateHolder, anonymousParty: AnonymousParty, path: CertPath) {
|
||||
val converter = JcaX509CertificateConverter()
|
||||
val expectedTrustAnchor = TrustAnchor(converter.getCertificate(trustedRoot), null)
|
||||
override fun registerAnonymousIdentity(anonymousParty: AnonymousParty, fullParty: PartyAndCertificate, path: CertPath) {
|
||||
require(path.certificates.isNotEmpty()) { "Certificate path must contain at least one certificate" }
|
||||
val target = path.certificates.last() as X509Certificate
|
||||
require(target.publicKey == anonymousParty.owningKey) { "Certificate path must end with anonymous party's public key" }
|
||||
// Validate the chain first, before we do anything clever with it
|
||||
val validator = CertPathValidator.getInstance("PKIX")
|
||||
val validatorParameters = PKIXParameters(setOf(expectedTrustAnchor)).apply {
|
||||
isRevocationEnabled = false
|
||||
val validatorParameters = if (trustAnchor != null) {
|
||||
PKIXParameters(setOf(trustAnchor))
|
||||
} else {
|
||||
// TODO: We should always require a full chain back to a trust anchor, but until we have a network
|
||||
// trust anchor everywhere, this will have to do.
|
||||
val converter = JcaX509CertificateConverter()
|
||||
PKIXParameters(setOf(TrustAnchor(converter.getCertificate(fullParty.certificate), null)))
|
||||
}
|
||||
validatorParameters.isRevocationEnabled = false
|
||||
val result = validator.validate(path, validatorParameters) as PKIXCertPathValidatorResult
|
||||
require(result.trustAnchor == expectedTrustAnchor)
|
||||
require(result.publicKey == anonymousParty.owningKey)
|
||||
val subjectCertificate = path.certificates.first()
|
||||
require(trustAnchor == null || result.trustAnchor == trustAnchor)
|
||||
require(result.publicKey == anonymousParty.owningKey) { "Certificate path validation must end at transaction key ${anonymousParty.owningKey.toStringShort()}, found ${result.publicKey.toStringShort()}" }
|
||||
require(subjectCertificate is X509Certificate && subjectCertificate.subject == fullParty.name) { "Subject of the transaction certificate must match the well known identity" }
|
||||
|
||||
log.trace { "Registering identity $fullParty" }
|
||||
|
||||
partyToPath[anonymousParty] = path
|
||||
keyToParties[anonymousParty.owningKey] = fullParty
|
||||
principalToParties[fullParty.name] = fullParty
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.crypto.sign
|
||||
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.KeyManagementService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
@ -57,7 +58,11 @@ class E2ETestKeyManagementService(val identityService: IdentityService,
|
||||
return keyPair.public
|
||||
}
|
||||
|
||||
override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> = freshKeyAndCert(this, identityService, identity, revocationEnabled)
|
||||
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> {
|
||||
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
|
||||
}
|
||||
|
||||
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
|
||||
|
||||
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
|
||||
return mutex.locked {
|
||||
|
@ -5,38 +5,49 @@ import net.corda.core.crypto.ContentSignerBuilder
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
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.KeyManagementService
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import java.security.Security
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Generates a new random [KeyPair], adds it to the internal key storage, then generates a corresponding
|
||||
* [X509Certificate] and adds it to the identity service.
|
||||
*
|
||||
* @param keyManagementService key service to use when generating the new key.
|
||||
* @param identityService identity service to use when registering the certificate.
|
||||
* @param identity identity to generate a key and certificate for. Must be an identity this node has CA privileges for.
|
||||
* @param subjectPublicKey public key of new identity.
|
||||
* @param issuerSigner a content signer for the issuer.
|
||||
* @param identityService issuer service to use when registering the certificate.
|
||||
* @param issuer issuer to generate a key and certificate for. Must be an identity this node has the private key for.
|
||||
* @param revocationEnabled whether to check revocation status of certificates in the certificate path.
|
||||
* @return X.509 certificate and path to the trust root.
|
||||
*/
|
||||
fun freshKeyAndCert(keyManagementService: KeyManagementService,
|
||||
identityService: IdentityService,
|
||||
identity: Party,
|
||||
revocationEnabled: Boolean = false): Pair<X509CertificateHolder, CertPath> {
|
||||
val ourPublicKey = keyManagementService.freshKey()
|
||||
// FIXME: Use the actual certificate for the identity the flow is presenting themselves as
|
||||
val issuerKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_IDENTITY_SIGNATURE_SCHEME)
|
||||
val issuerCertificate = X509Utilities.createSelfSignedCACertificate(identity.name, issuerKey)
|
||||
val ourCertificate = X509Utilities.createCertificate(CertificateType.IDENTITY, issuerCertificate, issuerKey, identity.name, ourPublicKey)
|
||||
fun freshCertificate(identityService: IdentityService,
|
||||
subjectPublicKey: PublicKey,
|
||||
issuer: PartyAndCertificate,
|
||||
issuerSigner: ContentSigner,
|
||||
revocationEnabled: Boolean = false): Pair<X509CertificateHolder, CertPath> {
|
||||
val issuerCertificate = issuer.certificate
|
||||
val window = X509Utilities.getCertificateValidityWindow(Duration.ZERO, Duration.ofDays(10 * 365), issuerCertificate)
|
||||
val ourCertificate = Crypto.createCertificate(CertificateType.IDENTITY, issuerCertificate.subject, issuerSigner, issuer.name, subjectPublicKey, window)
|
||||
val actualPublicKey = Crypto.toSupportedPublicKey(ourCertificate.subjectPublicKeyInfo)
|
||||
require(subjectPublicKey == actualPublicKey)
|
||||
val ourCertPath = X509Utilities.createCertificatePath(issuerCertificate, ourCertificate, revocationEnabled = revocationEnabled)
|
||||
identityService.registerPath(issuerCertificate,
|
||||
AnonymousParty(ourPublicKey),
|
||||
require(Arrays.equals(ourCertificate.subjectPublicKeyInfo.encoded, subjectPublicKey.encoded))
|
||||
identityService.registerAnonymousIdentity(AnonymousParty(subjectPublicKey),
|
||||
issuer,
|
||||
ourCertPath)
|
||||
return Pair(issuerCertificate, ourCertPath)
|
||||
}
|
||||
|
||||
fun getSigner(issuerKeyPair: KeyPair): ContentSigner {
|
||||
val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private)
|
||||
val provider = Security.getProvider(signatureScheme.providerName)
|
||||
return ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider)
|
||||
}
|
@ -5,7 +5,7 @@ import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.crypto.sign
|
||||
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.KeyManagementService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
@ -67,7 +67,12 @@ class PersistentKeyManagementService(val identityService: IdentityService,
|
||||
}
|
||||
return keyPair.public
|
||||
}
|
||||
override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> = freshKeyAndCert(this, identityService, identity, revocationEnabled)
|
||||
|
||||
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> {
|
||||
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
|
||||
}
|
||||
|
||||
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
|
||||
|
||||
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
|
||||
return mutex.locked {
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SignedData
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.MessageRecipients
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.NodeInfo
|
||||
@ -116,7 +117,7 @@ interface NetworkMapService {
|
||||
class InMemoryNetworkMapService(services: ServiceHubInternal, minimumPlatformVersion: Int)
|
||||
: AbstractNetworkMapService(services, minimumPlatformVersion) {
|
||||
|
||||
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = ConcurrentHashMap()
|
||||
override val nodeRegistrations: MutableMap<PartyAndCertificate, NodeRegistrationInfo> = ConcurrentHashMap()
|
||||
override val subscribers = ThreadBox(mutableMapOf<SingleMessageRecipient, LastAcknowledgeInfo>())
|
||||
|
||||
init {
|
||||
@ -142,7 +143,7 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal,
|
||||
private val logger = loggerFor<AbstractNetworkMapService>()
|
||||
}
|
||||
|
||||
protected abstract val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo>
|
||||
protected abstract val nodeRegistrations: MutableMap<PartyAndCertificate, NodeRegistrationInfo>
|
||||
|
||||
// Map from subscriber address, to most recently acknowledged update map version.
|
||||
protected abstract val subscribers: ThreadBox<MutableMap<SingleMessageRecipient, LastAcknowledgeInfo>>
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.node.services.network
|
||||
|
||||
import net.corda.core.ThreadBox
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.node.services.api.ServiceHubInternal
|
||||
import net.corda.node.utilities.*
|
||||
@ -22,22 +22,25 @@ class PersistentNetworkMapService(services: ServiceHubInternal, minimumPlatformV
|
||||
: AbstractNetworkMapService(services, minimumPlatformVersion) {
|
||||
|
||||
private object Table : JDBCHashedTable("${NODE_DATABASE_PREFIX}network_map_nodes") {
|
||||
val nodeParty = party("node_party_name", "node_party_key")
|
||||
val nodeParty = partyAndCertificate("node_party_name", "node_party_key", "node_party_certificate", "node_party_path")
|
||||
val registrationInfo = blob("node_registration_info")
|
||||
}
|
||||
|
||||
override val nodeRegistrations: MutableMap<Party, NodeRegistrationInfo> = synchronizedMap(object : AbstractJDBCHashMap<Party, NodeRegistrationInfo, Table>(Table, loadOnInit = true) {
|
||||
override val nodeRegistrations: MutableMap<PartyAndCertificate, NodeRegistrationInfo> = synchronizedMap(object : AbstractJDBCHashMap<PartyAndCertificate, NodeRegistrationInfo, Table>(Table, loadOnInit = true) {
|
||||
// TODO: We should understand an X500Name database field type, rather than manually doing the conversion ourselves
|
||||
override fun keyFromRow(row: ResultRow): Party = Party(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey])
|
||||
override fun keyFromRow(row: ResultRow): PartyAndCertificate = PartyAndCertificate(X500Name(row[table.nodeParty.name]), row[table.nodeParty.owningKey],
|
||||
row[table.nodeParty.certificate], row[table.nodeParty.certPath])
|
||||
|
||||
override fun valueFromRow(row: ResultRow): NodeRegistrationInfo = deserializeFromBlob(row[table.registrationInfo])
|
||||
|
||||
override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry<Party, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
|
||||
override fun addKeyToInsert(insert: InsertStatement, entry: Map.Entry<PartyAndCertificate, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
|
||||
insert[table.nodeParty.name] = entry.key.name.toString()
|
||||
insert[table.nodeParty.owningKey] = entry.key.owningKey
|
||||
insert[table.nodeParty.certPath] = entry.key.certPath
|
||||
insert[table.nodeParty.certificate] = entry.key.certificate
|
||||
}
|
||||
|
||||
override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry<Party, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
|
||||
override fun addValueToInsert(insert: InsertStatement, entry: Map.Entry<PartyAndCertificate, NodeRegistrationInfo>, finalizables: MutableList<() -> Unit>) {
|
||||
insert[table.registrationInfo] = serializeToBlob(entry.value, finalizables)
|
||||
}
|
||||
})
|
||||
|
@ -18,6 +18,7 @@ import net.corda.core.*
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.*
|
||||
import net.corda.core.utilities.debug
|
||||
import net.corda.core.utilities.loggerFor
|
||||
@ -339,7 +340,7 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
|
||||
waitingForResponse is WaitForLedgerCommit && message is ErrorSessionEnd
|
||||
}
|
||||
|
||||
private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: Party) {
|
||||
private fun onSessionInit(sessionInit: SessionInit, receivedMessage: ReceivedMessage, sender: PartyAndCertificate) {
|
||||
logger.trace { "Received $sessionInit from $sender" }
|
||||
val otherPartySessionId = sessionInit.initiatorSessionId
|
||||
|
||||
|
@ -3,7 +3,7 @@ package net.corda.node.services.transactions
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
@ -42,11 +42,11 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig,
|
||||
private val log = loggerFor<BFTNonValidatingNotaryService>()
|
||||
}
|
||||
|
||||
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
ServiceFlow(otherParty, client)
|
||||
}
|
||||
|
||||
private class ServiceFlow(val otherSide: Party, val client: BFTSMaRt.Client) : FlowLogic<Void?>() {
|
||||
private class ServiceFlow(val otherSide: PartyAndCertificate, val client: BFTSMaRt.Client) : FlowLogic<Void?>() {
|
||||
@Suspendable
|
||||
override fun call(): Void? {
|
||||
val stx = receive<FilteredTransaction>(otherSide).unwrap { it }
|
||||
@ -81,7 +81,7 @@ class BFTNonValidatingNotaryService(config: BFTSMaRtConfig,
|
||||
return response.serialize().bytes
|
||||
}
|
||||
|
||||
fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: Party): BFTSMaRt.ReplicaResponse {
|
||||
fun verifyAndCommitTx(ftx: FilteredTransaction, callerIdentity: PartyAndCertificate): BFTSMaRt.ReplicaResponse {
|
||||
return try {
|
||||
val id = ftx.rootHash
|
||||
val inputs = ftx.filteredLeaves.inputs
|
||||
|
@ -13,7 +13,7 @@ import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.SignedData
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -51,7 +51,7 @@ import java.util.*
|
||||
object BFTSMaRt {
|
||||
/** Sent from [Client] to [Server]. */
|
||||
@CordaSerializable
|
||||
data class CommitRequest(val tx: Any, val callerIdentity: Party)
|
||||
data class CommitRequest(val tx: Any, val callerIdentity: PartyAndCertificate)
|
||||
|
||||
/** Sent from [Server] to [Client]. */
|
||||
@CordaSerializable
|
||||
@ -83,7 +83,7 @@ object BFTSMaRt {
|
||||
* Sends a transaction commit request to the BFT cluster. The [proxy] will deliver the request to every
|
||||
* replica, and block until a sufficient number of replies are received.
|
||||
*/
|
||||
fun commitTransaction(transaction: Any, otherSide: Party): ClusterResponse {
|
||||
fun commitTransaction(transaction: Any, otherSide: PartyAndCertificate): ClusterResponse {
|
||||
require(transaction is FilteredTransaction || transaction is SignedTransaction) { "Unsupported transaction type: ${transaction.javaClass.name}" }
|
||||
val request = CommitRequest(transaction, otherSide)
|
||||
val responseBytes = proxy.invokeOrdered(request.serialize().bytes)
|
||||
@ -178,7 +178,7 @@ object BFTSMaRt {
|
||||
*/
|
||||
abstract fun executeCommand(command: ByteArray): ByteArray?
|
||||
|
||||
protected fun commitInputStates(states: List<StateRef>, txId: SecureHash, callerIdentity: Party) {
|
||||
protected fun commitInputStates(states: List<StateRef>, txId: SecureHash, callerIdentity: PartyAndCertificate) {
|
||||
log.debug { "Attempting to commit inputs for transaction: $txId" }
|
||||
val conflicts = mutableMapOf<StateRef, UniquenessProvider.ConsumingTx>()
|
||||
db.transaction {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
import net.corda.core.transactions.FilteredTransaction
|
||||
@ -9,7 +9,7 @@ import net.corda.core.utilities.unwrap
|
||||
import net.corda.flows.NotaryFlow
|
||||
import net.corda.flows.TransactionParts
|
||||
|
||||
class NonValidatingNotaryFlow(otherSide: Party,
|
||||
class NonValidatingNotaryFlow(otherSide: PartyAndCertificate,
|
||||
timeWindowChecker: TimeWindowChecker,
|
||||
uniquenessProvider: UniquenessProvider) : NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) {
|
||||
/**
|
||||
|
@ -2,13 +2,15 @@ package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
|
||||
interface NotaryService {
|
||||
|
||||
/**
|
||||
* Factory for producing notary service flows which have the corresponding sends and receives as NotaryFlow.Client.
|
||||
* The first parameter is the client [Party] making the request and the second is the platform version of the client's
|
||||
* node. Use this version parameter to provide backwards compatibility if the notary flow protocol changes.
|
||||
* The first parameter is the client [PartyAndCertificate] making the request and the second is the platform version
|
||||
* of the client's node. Use this version parameter to provide backwards compatibility if the notary flow protocol
|
||||
* changes.
|
||||
*/
|
||||
val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?>
|
||||
val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?>
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
|
||||
/** A non-validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
|
||||
@ -11,7 +11,7 @@ class RaftNonValidatingNotaryService(val timeWindowChecker: TimeWindowChecker,
|
||||
val type = SimpleNotaryService.type.getSubType("raft")
|
||||
}
|
||||
|
||||
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
|
||||
/** A validating notary service operated by a group of mutually trusting parties, uses the Raft algorithm to achieve consensus. */
|
||||
@ -11,7 +11,7 @@ class RaftValidatingNotaryService(val timeWindowChecker: TimeWindowChecker,
|
||||
val type = ValidatingNotaryService.type.getSubType("raft")
|
||||
}
|
||||
|
||||
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
@ -13,7 +13,7 @@ class SimpleNotaryService(val timeWindowChecker: TimeWindowChecker,
|
||||
val type = ServiceType.notary.getSubType("simple")
|
||||
}
|
||||
|
||||
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
NonValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package net.corda.node.services.transactions
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -17,7 +17,7 @@ import java.security.SignatureException
|
||||
* has its input states "blocked" by a transaction from another party, and needs to establish whether that transaction was
|
||||
* indeed valid.
|
||||
*/
|
||||
class ValidatingNotaryFlow(otherSide: Party,
|
||||
class ValidatingNotaryFlow(otherSide: PartyAndCertificate,
|
||||
timeWindowChecker: TimeWindowChecker,
|
||||
uniquenessProvider: UniquenessProvider) :
|
||||
NotaryFlow.Service(otherSide, timeWindowChecker, uniquenessProvider) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.node.services.transactions
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.node.services.TimeWindowChecker
|
||||
import net.corda.core.node.services.UniquenessProvider
|
||||
@ -13,7 +13,7 @@ class ValidatingNotaryService(val timeWindowChecker: TimeWindowChecker,
|
||||
val type = ServiceType.notary.getSubType("validating")
|
||||
}
|
||||
|
||||
override val serviceFlowFactory: (Party, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
override val serviceFlowFactory: (PartyAndCertificate, Int) -> FlowLogic<Void?> = { otherParty, _ ->
|
||||
ValidatingNotaryFlow(otherParty, timeWindowChecker, uniquenessProvider)
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.DUMMY_PUBKEY_1
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
import net.corda.jackson.JacksonSupport
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
@ -33,8 +33,7 @@ class InteractiveShellTest {
|
||||
override fun call() = a
|
||||
}
|
||||
|
||||
private val someCorpLegalName = MEGA_CORP.name
|
||||
private val ids = InMemoryIdentityService().apply { registerIdentity(Party(someCorpLegalName, DUMMY_PUBKEY_1)) }
|
||||
private val ids = InMemoryIdentityService(listOf(MEGA_CORP), trustRoot = DUMMY_CA.certificate)
|
||||
private val om = JacksonSupport.createInMemoryMapper(ids, YAMLFactory())
|
||||
|
||||
private fun check(input: String, expected: String) {
|
||||
@ -67,7 +66,7 @@ class InteractiveShellTest {
|
||||
fun flowTooManyParams() = check("b: 12, c: Yo, d: Bar", "")
|
||||
|
||||
@Test
|
||||
fun party() = check("party: \"$someCorpLegalName\"", someCorpLegalName.toString())
|
||||
fun party() = check("party: \"${MEGA_CORP.name}\"", MEGA_CORP.name.toString())
|
||||
|
||||
class DummyFSM(val logic: FlowA) : FlowStateMachine<Any?> {
|
||||
override fun <T : Any> sendAndReceive(receiveType: Class<T>, otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>, retrySend: Boolean): UntrustworthyData<T> {
|
||||
|
@ -13,6 +13,8 @@ import net.corda.core.flows.*
|
||||
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.map
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.*
|
||||
@ -493,7 +495,7 @@ class TwoPartyTradeFlowTests {
|
||||
}
|
||||
|
||||
@InitiatingFlow
|
||||
class SellerInitiator(val buyer: Party,
|
||||
class SellerInitiator(val buyer: PartyAndCertificate,
|
||||
val notary: NodeInfo,
|
||||
val assetToSell: StateAndRef<OwnableState>,
|
||||
val price: Amount<Currency>) : FlowLogic<SignedTransaction>() {
|
||||
@ -510,10 +512,10 @@ class TwoPartyTradeFlowTests {
|
||||
}
|
||||
|
||||
@InitiatedBy(SellerInitiator::class)
|
||||
class BuyerAcceptor(val seller: Party) : FlowLogic<SignedTransaction>() {
|
||||
class BuyerAcceptor(val seller: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
val (notary, price) = receive<Pair<Party, Amount<Currency>>>(seller).unwrap {
|
||||
val (notary, price) = receive<Pair<PartyAndCertificate, Amount<Currency>>>(seller).unwrap {
|
||||
require(serviceHub.networkMapCache.isNotary(it.first)) { "${it.first} is not a notary" }
|
||||
it
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.corda.node.services
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import net.corda.core.flows.FlowInitiator
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
|
@ -8,6 +8,7 @@ import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.seconds
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.core.utilities.getTestPartyAndCertificate
|
||||
import net.corda.flows.NotaryChangeFlow
|
||||
import net.corda.flows.StateReplacementException
|
||||
import net.corda.node.internal.AbstractNode
|
||||
@ -75,7 +76,7 @@ class NotaryChangeTests {
|
||||
@Test
|
||||
fun `should throw when a participant refuses to change Notary`() {
|
||||
val state = issueMultiPartyState(clientNodeA, clientNodeB, oldNotaryNode)
|
||||
val newEvilNotary = Party(X500Name("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK"), generateKeyPair().public)
|
||||
val newEvilNotary = getTestPartyAndCertificate(X500Name("CN=Evil Notary,O=Evil R3,OU=corda,L=London,C=UK"), generateKeyPair().public)
|
||||
val flow = NotaryChangeFlow(state, newEvilNotary)
|
||||
val future = clientNodeA.services.startFlow(flow)
|
||||
|
||||
|
@ -10,6 +10,7 @@ import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.VaultService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.ALICE_KEY
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.node.services.MockServiceHubInternal
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
@ -76,7 +77,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||
val dataSourceAndDatabase = configureDatabase(dataSourceProps)
|
||||
dataSource = dataSourceAndDatabase.first
|
||||
database = dataSourceAndDatabase.second
|
||||
val identityService = InMemoryIdentityService()
|
||||
val identityService = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||
val kms = MockKeyManagementService(identityService, ALICE_KEY)
|
||||
|
||||
database.transaction {
|
||||
|
@ -3,14 +3,15 @@ package net.corda.node.services.network
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.BOB
|
||||
import net.corda.core.utilities.*
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.testing.ALICE_PUBKEY
|
||||
import net.corda.testing.BOB_PUBKEY
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.junit.Test
|
||||
import java.security.cert.X509Certificate
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertNull
|
||||
@ -21,7 +22,7 @@ import kotlin.test.assertNull
|
||||
class InMemoryIdentityServiceTests {
|
||||
@Test
|
||||
fun `get all identities`() {
|
||||
val service = InMemoryIdentityService()
|
||||
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||
assertNull(service.getAllIdentities().firstOrNull())
|
||||
service.registerIdentity(ALICE)
|
||||
var expected = setOf<Party>(ALICE)
|
||||
@ -37,7 +38,7 @@ class InMemoryIdentityServiceTests {
|
||||
|
||||
@Test
|
||||
fun `get identity by key`() {
|
||||
val service = InMemoryIdentityService()
|
||||
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||
assertNull(service.partyFromKey(ALICE_PUBKEY))
|
||||
service.registerIdentity(ALICE)
|
||||
assertEquals(ALICE, service.partyFromKey(ALICE_PUBKEY))
|
||||
@ -46,15 +47,15 @@ class InMemoryIdentityServiceTests {
|
||||
|
||||
@Test
|
||||
fun `get identity by name with no registered identities`() {
|
||||
val service = InMemoryIdentityService()
|
||||
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||
assertNull(service.partyFromX500Name(ALICE.name))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get identity by name`() {
|
||||
val service = InMemoryIdentityService()
|
||||
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||
val identities = listOf("Node A", "Node B", "Node C")
|
||||
.map { Party(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) }
|
||||
.map { getTestPartyAndCertificate(X500Name("CN=$it,O=R3,OU=corda,L=London,C=UK"), generateKeyPair().public) }
|
||||
assertNull(service.partyFromX500Name(identities.first().name))
|
||||
identities.forEach { service.registerIdentity(it) }
|
||||
identities.forEach { assertEquals(it, service.partyFromX500Name(it.name)) }
|
||||
@ -68,7 +69,7 @@ class InMemoryIdentityServiceTests {
|
||||
val rootKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val rootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, rootKey)
|
||||
val txKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val service = InMemoryIdentityService()
|
||||
val service = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
|
||||
// TODO: Generate certificate with an EdDSA key rather than ECDSA
|
||||
val identity = Party(CertificateAndKeyPair(rootCert, rootKey))
|
||||
val txIdentity = AnonymousParty(txKey.public)
|
||||
@ -84,26 +85,26 @@ class InMemoryIdentityServiceTests {
|
||||
*/
|
||||
@Test
|
||||
fun `assert ownership`() {
|
||||
val service = InMemoryIdentityService(trustRoot = null as X509Certificate?)
|
||||
val aliceRootKey = Crypto.generateKeyPair()
|
||||
val aliceRootCert = X509Utilities.createSelfSignedCACertificate(ALICE.name, aliceRootKey)
|
||||
val aliceTxKey = Crypto.generateKeyPair()
|
||||
val aliceTxCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, aliceRootCert, aliceRootKey, ALICE.name, aliceTxKey.public)
|
||||
val aliceTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, aliceRootCert, aliceRootKey, ALICE.name, aliceTxKey.public)
|
||||
val aliceCertPath = X509Utilities.createCertificatePath(aliceRootCert, aliceTxCert, revocationEnabled = false)
|
||||
val alice = PartyAndCertificate(ALICE.name, aliceRootKey.public, aliceRootCert, aliceCertPath)
|
||||
|
||||
val anonymousAlice = AnonymousParty(aliceTxKey.public)
|
||||
service.registerAnonymousIdentity(anonymousAlice, alice, aliceCertPath)
|
||||
|
||||
val bobRootKey = Crypto.generateKeyPair()
|
||||
val bobRootCert = X509Utilities.createSelfSignedCACertificate(BOB.name, bobRootKey)
|
||||
val bobTxKey = Crypto.generateKeyPair()
|
||||
val bobTxCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, bobRootCert, bobRootKey, BOB.name, bobTxKey.public)
|
||||
val bobTxCert = X509Utilities.createCertificate(CertificateType.IDENTITY, bobRootCert, bobRootKey, BOB.name, bobTxKey.public)
|
||||
val bobCertPath = X509Utilities.createCertificatePath(bobRootCert, bobTxCert, revocationEnabled = false)
|
||||
val bob = PartyAndCertificate(BOB.name, bobRootKey.public, bobRootCert, bobCertPath)
|
||||
|
||||
val service = InMemoryIdentityService()
|
||||
val alice = Party(CertificateAndKeyPair(aliceRootCert, aliceRootKey))
|
||||
val anonymousAlice = AnonymousParty(aliceTxKey.public)
|
||||
val bob = Party(CertificateAndKeyPair(bobRootCert, bobRootKey))
|
||||
val anonymousBob = AnonymousParty(bobTxKey.public)
|
||||
|
||||
service.registerPath(aliceRootCert, anonymousAlice, aliceCertPath)
|
||||
service.registerPath(bobRootCert, anonymousBob, bobCertPath)
|
||||
service.registerAnonymousIdentity(anonymousBob, bob, bobCertPath)
|
||||
|
||||
// Verify that paths are verified
|
||||
service.assertOwnership(alice, anonymousAlice)
|
||||
@ -122,7 +123,7 @@ class InMemoryIdentityServiceTests {
|
||||
@Test
|
||||
fun `deanonymising a well known identity`() {
|
||||
val expected = ALICE
|
||||
val actual = InMemoryIdentityService().partyFromAnonymous(expected)
|
||||
val actual = InMemoryIdentityService(trustRoot = null as X509Certificate?).partyFromAnonymous(expected)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import net.corda.core.contracts.USD
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.unconsumedStates
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
@ -93,13 +93,13 @@ class DataVendingServiceTests {
|
||||
}
|
||||
|
||||
@InitiatingFlow
|
||||
private class NotifyTxFlow(val otherParty: Party, val stx: SignedTransaction) : FlowLogic<Unit>() {
|
||||
private class NotifyTxFlow(val otherParty: PartyAndCertificate, val stx: SignedTransaction) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() = send(otherParty, NotifyTxRequest(stx))
|
||||
}
|
||||
|
||||
@InitiatedBy(NotifyTxFlow::class)
|
||||
private class InitiateNotifyTxFlow(val otherParty: Party) : FlowLogic<Unit>() {
|
||||
private class InitiateNotifyTxFlow(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() = subFlow(NotifyTransactionHandler(otherParty))
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.FlowSessionException
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.MessageRecipients
|
||||
import net.corda.core.node.services.PartyInfo
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
@ -673,10 +674,10 @@ class FlowFrameworkTests {
|
||||
|
||||
private inline fun <reified P : FlowLogic<*>> MockNode.registerFlowFactory(
|
||||
initiatingFlowClass: KClass<out FlowLogic<*>>,
|
||||
noinline flowFactory: (Party) -> P): ListenableFuture<P>
|
||||
noinline flowFactory: (PartyAndCertificate) -> P): ListenableFuture<P>
|
||||
{
|
||||
val observable = registerFlowFactory(initiatingFlowClass.java, object : InitiatedFlowFactory<P> {
|
||||
override fun createFlow(platformVersion: Int, otherParty: Party, sessionInit: SessionInit): P {
|
||||
override fun createFlow(platformVersion: Int, otherParty: PartyAndCertificate, sessionInit: SessionInit): P {
|
||||
return flowFactory(otherParty)
|
||||
}
|
||||
}, P::class.java, track = true)
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.crypto.*
|
||||
import net.corda.core.exists
|
||||
import net.corda.core.mapToArray
|
||||
import net.corda.core.utilities.ALICE
|
||||
import net.corda.core.utilities.getTestPartyAndCertificate
|
||||
import net.corda.testing.TestNodeConfiguration
|
||||
import net.corda.testing.getTestX509Name
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
@ -14,6 +15,7 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.security.cert.Certificate
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.SchedulableFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.seconds
|
||||
@ -30,8 +31,7 @@ object FixingFlow {
|
||||
* who does what in the flow.
|
||||
*/
|
||||
@InitiatedBy(FixingRoleDecider::class)
|
||||
class Fixer(override val otherParty: Party) : TwoPartyDealFlow.Secondary<FixingSession>() {
|
||||
override val progressTracker: ProgressTracker = TwoPartyDealFlow.Secondary.tracker()
|
||||
class Fixer(override val otherParty: PartyAndCertificate) : TwoPartyDealFlow.Secondary<FixingSession>() {
|
||||
|
||||
private lateinit var txState: TransactionState<*>
|
||||
private lateinit var deal: FixableDealState
|
||||
@ -97,7 +97,7 @@ object FixingFlow {
|
||||
* is just the "side" of the flow run by the party with the floating leg as a way of deciding who
|
||||
* does what in the flow.
|
||||
*/
|
||||
class Floater(override val otherParty: Party,
|
||||
class Floater(override val otherParty: PartyAndCertificate,
|
||||
override val payload: FixingSession,
|
||||
override val progressTracker: ProgressTracker = TwoPartyDealFlow.Primary.tracker()) : TwoPartyDealFlow.Primary() {
|
||||
|
||||
|
@ -15,8 +15,10 @@ import net.corda.core.flows.FlowStateMachine
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.services.linearHeadsOfType
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.flows.TwoPartyDealFlow.Acceptor
|
||||
import net.corda.flows.TwoPartyDealFlow.AutoOffer
|
||||
import net.corda.flows.TwoPartyDealFlow.Instigator
|
||||
@ -46,7 +48,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
||||
|
||||
override fun startMainSimulation(): ListenableFuture<Unit> {
|
||||
val future = SettableFuture.create<Unit>()
|
||||
om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentity }))
|
||||
om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentity }, trustRoot = DUMMY_CA.certificate))
|
||||
|
||||
startIRSDealBetween(0, 1).success {
|
||||
// Next iteration is a pause.
|
||||
@ -129,7 +131,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
||||
node2.registerInitiatedFlow(FixingFlow.Fixer::class.java)
|
||||
|
||||
@InitiatingFlow
|
||||
class StartDealFlow(val otherParty: Party,
|
||||
class StartDealFlow(val otherParty: PartyAndCertificate,
|
||||
val payload: AutoOffer,
|
||||
val myKey: PublicKey) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
|
@ -9,6 +9,7 @@ import net.corda.core.crypto.*
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.utilities.DUMMY_MAP
|
||||
@ -35,7 +36,7 @@ import javax.ws.rs.core.Response
|
||||
|
||||
@Path("simmvaluationdemo")
|
||||
class PortfolioApi(val rpc: CordaRPCOps) {
|
||||
private val ownParty: Party get() = rpc.nodeIdentity().legalIdentity
|
||||
private val ownParty: PartyAndCertificate get() = rpc.nodeIdentity().legalIdentity
|
||||
private val portfolioUtils = PortfolioApiUtils(ownParty)
|
||||
|
||||
private inline fun <reified T : DealState> dealsWith(party: AbstractParty): List<StateAndRef<T>> {
|
||||
@ -48,7 +49,7 @@ class PortfolioApi(val rpc: CordaRPCOps) {
|
||||
* DSL to get a party and then executing the passed function with the party as a parameter.
|
||||
* Used as such: withParty(name) { doSomethingWith(it) }
|
||||
*/
|
||||
private fun withParty(partyName: String, func: (Party) -> Response): Response {
|
||||
private fun withParty(partyName: String, func: (PartyAndCertificate) -> Response): Response {
|
||||
val otherParty = rpc.partyFromKey(parsePublicKeyBase58(partyName))
|
||||
return if (otherParty != null) {
|
||||
func(otherParty)
|
||||
|
@ -6,6 +6,7 @@ import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.unwrap
|
||||
@ -20,7 +21,7 @@ object IRSTradeFlow {
|
||||
|
||||
@InitiatingFlow
|
||||
@StartableByRPC
|
||||
class Requester(val swap: SwapData, val otherParty: Party) : FlowLogic<SignedTransaction>() {
|
||||
class Requester(val swap: SwapData, val otherParty: PartyAndCertificate) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction {
|
||||
require(serviceHub.networkMapCache.notaryNodes.isNotEmpty()) { "No notary nodes registered" }
|
||||
|
@ -15,6 +15,7 @@ import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.PluginServiceHub
|
||||
import net.corda.core.node.services.dealsWith
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -185,7 +186,7 @@ object SimmFlow {
|
||||
* Receives and validates a portfolio and comes to consensus over the portfolio initial margin using SIMM.
|
||||
*/
|
||||
@InitiatedBy(Requester::class)
|
||||
class Receiver(val replyToParty: Party) : FlowLogic<Unit>() {
|
||||
class Receiver(val replyToParty: PartyAndCertificate) : FlowLogic<Unit>() {
|
||||
lateinit var ownParty: Party
|
||||
lateinit var offer: OfferMessage
|
||||
|
||||
|
@ -3,6 +3,7 @@ package net.corda.vega.flows
|
||||
import net.corda.core.contracts.StateAndRef
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.seconds
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.flows.AbstractStateReplacementFlow
|
||||
@ -26,7 +27,7 @@ object StateRevisionFlow {
|
||||
}
|
||||
}
|
||||
|
||||
open class Receiver<in T>(otherParty: Party) : AbstractStateReplacementFlow.Acceptor<T>(otherParty) {
|
||||
open class Receiver<in T>(otherParty: PartyAndCertificate) : AbstractStateReplacementFlow.Acceptor<T>(otherParty) {
|
||||
override fun verifyProposal(proposal: AbstractStateReplacementFlow.Proposal<T>) {
|
||||
val proposedTx = proposal.stx.tx
|
||||
val state = proposal.stateRef
|
||||
|
@ -7,7 +7,7 @@ import net.corda.core.contracts.TransactionGraphSearch
|
||||
import net.corda.core.div
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.Emoji
|
||||
@ -17,7 +17,7 @@ import net.corda.flows.TwoPartyTradeFlow
|
||||
import java.util.*
|
||||
|
||||
@InitiatedBy(SellerFlow::class)
|
||||
class BuyerFlow(val otherParty: Party) : FlowLogic<Unit>() {
|
||||
class BuyerFlow(val otherParty: PartyAndCertificate) : FlowLogic<Unit>() {
|
||||
|
||||
object STARTING_BUY : ProgressTracker.Step("Seller connected, purchasing commercial paper asset")
|
||||
|
||||
|
@ -12,6 +12,7 @@ import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.seconds
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -24,10 +25,10 @@ import java.util.*
|
||||
|
||||
@InitiatingFlow
|
||||
@StartableByRPC
|
||||
class SellerFlow(val otherParty: Party,
|
||||
class SellerFlow(val otherParty: PartyAndCertificate,
|
||||
val amount: Amount<Currency>,
|
||||
override val progressTracker: ProgressTracker) : FlowLogic<SignedTransaction>() {
|
||||
constructor(otherParty: Party, amount: Amount<Currency>) : this(otherParty, amount, tracker())
|
||||
constructor(otherParty: PartyAndCertificate, amount: Amount<Currency>) : this(otherParty, amount, tracker())
|
||||
|
||||
companion object {
|
||||
val PROSPECTUS_HASH = SecureHash.parse("decd098666b9657314870e192ced0c3519c2c9d395507a238338f8d003929de9")
|
||||
|
@ -9,7 +9,7 @@ import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.VersionInfo
|
||||
import net.corda.core.node.services.IdentityService
|
||||
@ -66,22 +66,22 @@ 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: Party get() = Party(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY)
|
||||
val MINI_CORP: Party get() = Party(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY)
|
||||
val MEGA_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MegaCorp"), MEGA_CORP_PUBKEY)
|
||||
val MINI_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("MiniCorp"), MINI_CORP_PUBKEY)
|
||||
|
||||
val BOC_KEY: KeyPair by lazy { generateKeyPair() }
|
||||
val BOC_PUBKEY: PublicKey get() = BOC_KEY.public
|
||||
val BOC: Party get() = Party(getTestX509Name("BankOfCorda"), BOC_PUBKEY)
|
||||
val BOC: PartyAndCertificate get() = getTestPartyAndCertificate(getTestX509Name("BankOfCorda"), BOC_PUBKEY)
|
||||
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: Party get() = Party(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY)
|
||||
val BIG_CORP: PartyAndCertificate get() = getTestPartyAndCertificate(X509Utilities.getDevX509Name("BigCorporation"), BIG_CORP_PUBKEY)
|
||||
val BIG_CORP_PARTY_REF = BIG_CORP.ref(OpaqueBytes.of(1)).reference
|
||||
|
||||
val ALL_TEST_KEYS: List<KeyPair> get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY)
|
||||
|
||||
val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
|
||||
val MOCK_IDENTITY_SERVICE: IdentityService get() = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY), emptyMap(), DUMMY_CA.certificate)
|
||||
|
||||
val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor")
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
||||
import net.corda.core.*
|
||||
import net.corda.core.crypto.entropyToKeyPair
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.RPCOps
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
@ -14,6 +15,7 @@ import net.corda.core.node.PhysicalLocation
|
||||
import net.corda.core.node.ServiceEntry
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import net.corda.core.utilities.getTestPartyAndCertificate
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.internal.AbstractNode
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
@ -38,6 +40,7 @@ import org.slf4j.Logger
|
||||
import java.math.BigInteger
|
||||
import java.nio.file.FileSystem
|
||||
import java.security.KeyPair
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
@ -68,7 +71,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
||||
// A unique identifier for this network to segregate databases with the same nodeID but different networks.
|
||||
private val networkId = random63BitValue()
|
||||
|
||||
val identities = ArrayList<Party>()
|
||||
val identities = ArrayList<PartyAndCertificate>()
|
||||
|
||||
private val _nodes = ArrayList<MockNode>()
|
||||
/** A read only view of the current set of executing nodes. */
|
||||
@ -162,7 +165,8 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
||||
.getOrThrow()
|
||||
}
|
||||
|
||||
override fun makeIdentityService() = InMemoryIdentityService(mockNet.identities)
|
||||
// TODO: Specify a CA to validate registration against
|
||||
override fun makeIdentityService() = InMemoryIdentityService(mockNet.identities, trustRoot = null as X509Certificate?)
|
||||
|
||||
override fun makeVaultService(dataSourceProperties: Properties): VaultService = NodeVaultService(services, dataSourceProperties)
|
||||
|
||||
@ -187,7 +191,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
||||
val override = overrideServices[it.info]
|
||||
if (override != null) {
|
||||
// TODO: Store the key
|
||||
ServiceEntry(it.info, Party(it.identity.name, override.public))
|
||||
ServiceEntry(it.info, getTestPartyAndCertificate(it.identity.name, override.public))
|
||||
} else {
|
||||
it
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package net.corda.testing.node
|
||||
import net.corda.core.contracts.Attachment
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.ServiceHub
|
||||
@ -11,10 +11,12 @@ import net.corda.core.node.services.*
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.DUMMY_CA
|
||||
import net.corda.core.utilities.DUMMY_NOTARY
|
||||
import net.corda.core.utilities.getTestPartyAndCertificate
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.node.services.keys.freshKeyAndCert
|
||||
import net.corda.node.services.keys.freshCertificate
|
||||
import net.corda.node.services.keys.getSigner
|
||||
import net.corda.node.services.persistence.InMemoryStateMachineRecordedTransactionMappingStorage
|
||||
import net.corda.node.services.schema.HibernateObserver
|
||||
import net.corda.node.services.schema.NodeSchemaService
|
||||
@ -24,6 +26,7 @@ import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MINI_CORP
|
||||
import net.corda.testing.MOCK_VERSION_INFO
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
import rx.Observable
|
||||
import rx.subjects.PublishSubject
|
||||
import java.io.ByteArrayInputStream
|
||||
@ -63,7 +66,8 @@ open class MockServices(vararg val keys: KeyPair) : ServiceHub {
|
||||
}
|
||||
|
||||
override val storageService: TxWritableStorageService = MockStorageService()
|
||||
override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY))
|
||||
override final val identityService: IdentityService = InMemoryIdentityService(listOf(MEGA_CORP, MINI_CORP, DUMMY_NOTARY),
|
||||
trustRoot = DUMMY_CA.certificate)
|
||||
override val keyManagementService: KeyManagementService = MockKeyManagementService(identityService, *keys)
|
||||
|
||||
override val vaultService: VaultService get() = throw UnsupportedOperationException()
|
||||
@ -96,10 +100,12 @@ class MockKeyManagementService(val identityService: IdentityService,
|
||||
return k.public
|
||||
}
|
||||
|
||||
override fun freshKeyAndCert(identity: Party, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> {
|
||||
return freshKeyAndCert(this, identityService, identity, revocationEnabled)
|
||||
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): Pair<X509CertificateHolder, CertPath> {
|
||||
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
|
||||
}
|
||||
|
||||
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))
|
||||
|
||||
private fun getSigningKeyPair(publicKey: PublicKey): KeyPair {
|
||||
val pk = publicKey.keys.first { keyStore.containsKey(it) }
|
||||
return KeyPair(pk, keyStore[pk]!!)
|
||||
|
@ -3,7 +3,6 @@ package net.corda.testing.node
|
||||
import com.codahale.metrics.MetricRegistry
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import net.corda.core.crypto.CertificateAndKeyPair
|
||||
import net.corda.core.crypto.commonName
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.messaging.RPCOps
|
||||
@ -22,6 +21,7 @@ import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.node.utilities.transaction
|
||||
import net.corda.testing.MOCK_VERSION_INFO
|
||||
import net.corda.testing.freeLocalHostAndPort
|
||||
import org.bouncycastle.cert.X509CertificateHolder
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import java.io.Closeable
|
||||
import java.security.KeyPair
|
||||
@ -33,14 +33,14 @@ import kotlin.concurrent.thread
|
||||
*/
|
||||
class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(),
|
||||
rpcAddress: HostAndPort = freeLocalHostAndPort(),
|
||||
networkRoot: CertificateAndKeyPair? = null) : AutoCloseable {
|
||||
trustRoot: X509CertificateHolder? = null) : AutoCloseable {
|
||||
|
||||
private val databaseWithCloseable: Pair<Closeable, Database> = configureDatabase(config.dataSourceProperties)
|
||||
val database: Database get() = databaseWithCloseable.second
|
||||
val userService = RPCUserServiceImpl(config.rpcUsers)
|
||||
val monitoringService = MonitoringService(MetricRegistry())
|
||||
val identity: KeyPair = generateKeyPair()
|
||||
val identityService: IdentityService = InMemoryIdentityService()
|
||||
val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot)
|
||||
val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity))
|
||||
val executor = ServiceAffinityExecutor(config.myLegalName.commonName, 1)
|
||||
val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService)
|
||||
|
@ -183,7 +183,7 @@ class NewTransaction : Fragment() {
|
||||
// Issuer
|
||||
issuerLabel.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull)
|
||||
issuerChoiceBox.apply {
|
||||
items = issuers.map { it.legalIdentity }.unique().sorted()
|
||||
items = issuers.map { it.legalIdentity as Party }.unique().sorted()
|
||||
converter = stringConverter { PartyNameFormatter.short.format(it.name) }
|
||||
visibleProperty().bind(transactionTypeCB.valueProperty().map { it == CashTransaction.Pay })
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user