mirror of
https://github.com/corda/corda.git
synced 2025-06-17 14:48:16 +00:00
Correct behaviour of anonymousToParty()
Correct behaviour of anonymousToParty() in identity API; it previously presumed any Party was a well known identity, now it tries to look up the well known identity irrespective of whether it's been given a full party or not.
This commit is contained in:
@ -16,6 +16,7 @@ import java.security.cert.*
|
|||||||
interface IdentityService {
|
interface IdentityService {
|
||||||
val trustRoot: X509Certificate
|
val trustRoot: X509Certificate
|
||||||
val trustRootHolder: X509CertificateHolder
|
val trustRootHolder: X509CertificateHolder
|
||||||
|
val trustAnchor: TrustAnchor
|
||||||
val caCertStore: CertStore
|
val caCertStore: CertStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,11 +32,12 @@ interface IdentityService {
|
|||||||
/**
|
/**
|
||||||
* Verify and then store an identity.
|
* Verify and then store an identity.
|
||||||
*
|
*
|
||||||
* @param identity a party representing a legal entity and the certificate path linking them to the network trust root.
|
* @param identity a party and the certificate path linking them to the network trust root.
|
||||||
|
* @return the issuing entity, if known.
|
||||||
* @throws IllegalArgumentException if the certificate path is invalid.
|
* @throws IllegalArgumentException if the certificate path is invalid.
|
||||||
*/
|
*/
|
||||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||||
fun verifyAndRegisterIdentity(identity: PartyAndCertificate)
|
fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with
|
* Asserts that an anonymous party maps to the given full party, by looking up the certificate chain associated with
|
||||||
@ -62,9 +64,11 @@ interface IdentityService {
|
|||||||
/**
|
/**
|
||||||
* Get the certificate and path for a well known identity.
|
* Get the certificate and path for a well known identity.
|
||||||
*
|
*
|
||||||
* @return the party and certificate, or null if unknown.
|
* @return the party and certificate.
|
||||||
|
* @throws IllegalArgumentException if the certificate and path are unknown. This should never happen for a well
|
||||||
|
* known identity.
|
||||||
*/
|
*/
|
||||||
fun certificateFromParty(party: Party): PartyAndCertificate?
|
fun certificateFromParty(party: Party): PartyAndCertificate
|
||||||
|
|
||||||
// There is no method for removing identities, as once we are made aware of a Party we want to keep track of them
|
// There is no method for removing identities, as once we are made aware of a Party we want to keep track of them
|
||||||
// indefinitely. It may be that in the long term we need to drop or archive very old Party information for space,
|
// indefinitely. It may be that in the long term we need to drop or archive very old Party information for space,
|
||||||
|
@ -44,9 +44,8 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
|
|||||||
*/
|
*/
|
||||||
override val caCertStore: CertStore
|
override val caCertStore: CertStore
|
||||||
override val trustRootHolder = X509CertificateHolder(trustRoot.encoded)
|
override val trustRootHolder = X509CertificateHolder(trustRoot.encoded)
|
||||||
private val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
|
override val trustAnchor: TrustAnchor = TrustAnchor(trustRoot, null)
|
||||||
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
private val keyToParties = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
||||||
private val keyToIssuingParty = ConcurrentHashMap<PublicKey, PartyAndCertificate>()
|
|
||||||
private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
|
private val principalToParties = ConcurrentHashMap<X500Name, PartyAndCertificate>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -56,16 +55,17 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
|
|||||||
principalToParties.putAll(identities.associateBy { it.name })
|
principalToParties.putAll(identities.associateBy { it.name })
|
||||||
confidentialIdentities.forEach { identity ->
|
confidentialIdentities.forEach { identity ->
|
||||||
require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" }
|
require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" }
|
||||||
keyToIssuingParty[identity.owningKey] = keyToParties[identity.certPath.certificates[1].publicKey]!!
|
|
||||||
principalToParties.computeIfAbsent(identity.name) { identity }
|
principalToParties.computeIfAbsent(identity.name) { identity }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerIdentity(party: PartyAndCertificate) = verifyAndRegisterIdentity(party)
|
override fun registerIdentity(party: PartyAndCertificate) {
|
||||||
|
verifyAndRegisterIdentity(party)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Check the certificate validation logic
|
// TODO: Check the certificate validation logic
|
||||||
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
@Throws(CertificateExpiredException::class, CertificateNotYetValidException::class, InvalidAlgorithmParameterException::class)
|
||||||
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate) {
|
override fun verifyAndRegisterIdentity(identity: PartyAndCertificate): PartyAndCertificate? {
|
||||||
require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" }
|
require(identity.certPath.certificates.size >= 2) { "Certificate path must at least include subject and issuing certificates" }
|
||||||
// Validate the chain first, before we do anything clever with it
|
// Validate the chain first, before we do anything clever with it
|
||||||
identity.verify(trustAnchor)
|
identity.verify(trustAnchor)
|
||||||
@ -74,25 +74,32 @@ class InMemoryIdentityService(identities: Iterable<PartyAndCertificate> = emptyS
|
|||||||
require(Arrays.equals(identity.certificate.subjectPublicKeyInfo.encoded, identity.owningKey.encoded)) { "Party certificate must end with party's public key" }
|
require(Arrays.equals(identity.certificate.subjectPublicKeyInfo.encoded, identity.owningKey.encoded)) { "Party certificate must end with party's public key" }
|
||||||
|
|
||||||
keyToParties[identity.owningKey] = identity
|
keyToParties[identity.owningKey] = identity
|
||||||
// TODO: This map should only be deanonymised parties, not all issuers, but we have no good way of checking for
|
|
||||||
// confidential vs anonymous identities
|
|
||||||
val issuer = keyToParties[identity.certPath.certificates[1].publicKey]
|
|
||||||
if (issuer != null) {
|
|
||||||
keyToIssuingParty[identity.owningKey] = issuer
|
|
||||||
}
|
|
||||||
// Always keep the first party we registered, as that's the well known identity
|
// Always keep the first party we registered, as that's the well known identity
|
||||||
principalToParties.computeIfAbsent(identity.name) { identity }
|
principalToParties.computeIfAbsent(identity.name) { identity }
|
||||||
|
return keyToParties[identity.certPath.certificates[1].publicKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = keyToParties[owningKey]
|
override fun certificateFromKey(owningKey: PublicKey): PartyAndCertificate? = keyToParties[owningKey]
|
||||||
override fun certificateFromParty(party: Party): PartyAndCertificate? = principalToParties[party.name]
|
override fun certificateFromParty(party: Party): PartyAndCertificate = principalToParties[party.name] ?: throw IllegalArgumentException("Unknown identity ${party.name}")
|
||||||
|
|
||||||
// We give the caller a copy of the data set to avoid any locking problems
|
// We give the caller a copy of the data set to avoid any locking problems
|
||||||
override fun getAllIdentities(): Iterable<PartyAndCertificate> = java.util.ArrayList(keyToParties.values)
|
override fun getAllIdentities(): Iterable<PartyAndCertificate> = java.util.ArrayList(keyToParties.values)
|
||||||
|
|
||||||
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party
|
override fun partyFromKey(key: PublicKey): Party? = keyToParties[key]?.party
|
||||||
override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]?.party
|
override fun partyFromX500Name(principal: X500Name): Party? = principalToParties[principal]?.party
|
||||||
override fun partyFromAnonymous(party: AbstractParty) = party as? Party ?: keyToIssuingParty[party.owningKey]?.party
|
override fun partyFromAnonymous(party: AbstractParty): Party? {
|
||||||
|
// Expand the anonymous party to a full party (i.e. has a name) if possible
|
||||||
|
val candidate = party as? Party ?: keyToParties[party.owningKey]?.party
|
||||||
|
// TODO: This should be done via the network map cache, which is the authoritative source of well known identities
|
||||||
|
// Look up the well known identity for that name
|
||||||
|
return if (candidate != null) {
|
||||||
|
// If we have a well known identity by that name, use it in preference to the candidate. Otherwise default
|
||||||
|
// back to the candidate.
|
||||||
|
principalToParties[candidate.name]?.party ?: candidate
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
|
override fun partyFromAnonymous(partyRef: PartyAndReference) = partyFromAnonymous(partyRef.party)
|
||||||
override fun requirePartyFromAnonymous(party: AbstractParty): Party {
|
override fun requirePartyFromAnonymous(party: AbstractParty): Party {
|
||||||
return partyFromAnonymous(party) ?: throw IllegalStateException("Could not deanonymise party ${party.owningKey.toStringShort()}")
|
return partyFromAnonymous(party) ?: throw IllegalStateException("Could not deanonymise party ${party.owningKey.toStringShort()}")
|
||||||
|
@ -356,7 +356,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
|||||||
nodes += createPartyNode(mapAddress)
|
nodes += createPartyNode(mapAddress)
|
||||||
}
|
}
|
||||||
nodes.forEach { itNode ->
|
nodes.forEach { itNode ->
|
||||||
nodes.map { it.info.legalIdentityAndCert }.forEach(itNode.services.identityService::verifyAndRegisterIdentity)
|
nodes.map { it.info.legalIdentityAndCert }.map(itNode.services.identityService::verifyAndRegisterIdentity)
|
||||||
}
|
}
|
||||||
return BasketOfNodes(nodes, notaryNode, mapNode)
|
return BasketOfNodes(nodes, notaryNode, mapNode)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user