Merge pull request #6285 from corda/denis/CORDA-3818-sync-identity-service

CORDA-3818: Synchronize OS implementation of PublicKeyToOwningIdentityCache with CE
This commit is contained in:
Denis Rekalov 2020-05-28 14:21:04 +01:00 committed by GitHub
commit 499c09e77b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 19 additions and 59 deletions

View File

@ -11,7 +11,7 @@ interface PublicKeyToOwningIdentityCache {
/** /**
* Obtain the owning identity for a public key. * Obtain the owning identity for a public key.
* *
* If the key is unknown to the node, then this will return null. * If the key is unknown to the node, then this will return [KeyOwningIdentity.UnmappedIdentity].
*/ */
operator fun get(key: PublicKey): KeyOwningIdentity? operator fun get(key: PublicKey): KeyOwningIdentity
} }

View File

@ -413,6 +413,9 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
return database.transaction { return database.transaction {
log.info("Linking: ${publicKey.hash} to ${party.name}") log.info("Linking: ${publicKey.hash} to ${party.name}")
keyToName[publicKey.toStringShort()] = party.name keyToName[publicKey.toStringShort()] = party.name
if (party == wellKnownPartyFromX500Name(ourNames.first())) {
_pkToIdCache[publicKey] = KeyOwningIdentity.UnmappedIdentity
}
} }
} }
@ -422,7 +425,7 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
} }
override fun externalIdForPublicKey(publicKey: PublicKey): UUID? { override fun externalIdForPublicKey(publicKey: PublicKey): UUID? {
return _pkToIdCache[publicKey]?.uuid return _pkToIdCache[publicKey].uuid
} }
private fun publicKeysForExternalId(externalId: UUID, table: Class<*>): List<PublicKey> { private fun publicKeysForExternalId(externalId: UUID, table: Class<*>): List<PublicKey> {

View File

@ -5,12 +5,9 @@ import net.corda.core.crypto.toStringShort
import net.corda.core.internal.NamedCacheFactory import net.corda.core.internal.NamedCacheFactory
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug import net.corda.core.utilities.debug
import net.corda.node.services.identity.PersistentIdentityService
import net.corda.node.services.keys.BasicHSMKeyManagementService
import net.corda.nodeapi.internal.KeyOwningIdentity import net.corda.nodeapi.internal.KeyOwningIdentity
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
import java.security.PublicKey import java.security.PublicKey
import java.util.*
/** /**
* The [PublicKeyToOwningIdentityCacheImpl] provides a caching layer over the pk_hash_to_external_id table. Gets will attempt to read an * The [PublicKeyToOwningIdentityCacheImpl] provides a caching layer over the pk_hash_to_external_id table. Gets will attempt to read an
@ -22,42 +19,10 @@ class PublicKeyToOwningIdentityCacheImpl(private val database: CordaPersistence,
val log = contextLogger() val log = contextLogger()
} }
private val cache = cacheFactory.buildNamed<PublicKey, KeyOwningIdentity>(Caffeine.newBuilder(), "PublicKeyToOwningIdentityCache_cache") private val cache = cacheFactory.buildNamed<PublicKey, KeyOwningIdentity>(
Caffeine.newBuilder(),
/** "PublicKeyToOwningIdentityCache_cache"
* Establish whether a public key is one of the node's identity keys, by looking in the node's identity database table. )
*/
private fun isKeyIdentityKey(key: PublicKey): Boolean {
return database.transaction {
val criteriaBuilder = session.criteriaBuilder
val criteriaQuery = criteriaBuilder.createQuery(Long::class.java)
val queryRoot = criteriaQuery.from(PersistentIdentityService.PersistentPublicKeyHashToCertificate::class.java)
criteriaQuery.select(criteriaBuilder.count(queryRoot))
criteriaQuery.where(
criteriaBuilder.equal(queryRoot.get<String>(PersistentIdentityService.PersistentPublicKeyHashToCertificate::publicKeyHash.name), key.toStringShort())
)
val query = session.createQuery(criteriaQuery)
query.uniqueResult() > 0
}
}
/**
* Check to see if the key belongs to one of the key pairs in the node_our_key_pairs table. These keys may relate to confidential
* identities.
*/
private fun isKeyPartOfNodeKeyPairs(key: PublicKey): Boolean {
return database.transaction {
val criteriaBuilder = session.criteriaBuilder
val criteriaQuery = criteriaBuilder.createQuery(Long::class.java)
val queryRoot = criteriaQuery.from(BasicHSMKeyManagementService.PersistentKey::class.java)
criteriaQuery.select(criteriaBuilder.count(queryRoot))
criteriaQuery.where(
criteriaBuilder.equal(queryRoot.get<String>(BasicHSMKeyManagementService.PersistentKey::publicKeyHash.name), key.toStringShort())
)
val query = session.createQuery(criteriaQuery)
query.uniqueResult() > 0
}
}
/** /**
* Return the owning identity associated with a given key. * Return the owning identity associated with a given key.
@ -65,25 +30,17 @@ class PublicKeyToOwningIdentityCacheImpl(private val database: CordaPersistence,
* This method caches the result of a database lookup to prevent multiple database accesses for the same key. This assumes that once a * This method caches the result of a database lookup to prevent multiple database accesses for the same key. This assumes that once a
* key is generated, the UUID assigned to it is never changed. * key is generated, the UUID assigned to it is never changed.
*/ */
override operator fun get(key: PublicKey): KeyOwningIdentity? { override operator fun get(key: PublicKey): KeyOwningIdentity {
return cache.asMap().computeIfAbsent(key) { return cache.asMap().computeIfAbsent(key) {
database.transaction { database.transaction {
val criteriaBuilder = session.criteriaBuilder val uuid = session.find(PublicKeyHashToExternalId::class.java, key.toStringShort())?.externalId
val criteriaQuery = criteriaBuilder.createQuery(UUID::class.java) if (uuid != null) {
val queryRoot = criteriaQuery.from(PublicKeyHashToExternalId::class.java)
criteriaQuery.select(queryRoot.get(PublicKeyHashToExternalId::externalId.name))
criteriaQuery.where(
criteriaBuilder.equal(queryRoot.get<String>(PublicKeyHashToExternalId::publicKeyHash.name), key.toStringShort())
)
val query = session.createQuery(criteriaQuery)
val uuid = query.uniqueResult()
if (uuid != null || isKeyPartOfNodeKeyPairs(key) || isKeyIdentityKey(key)) {
val signingEntity = KeyOwningIdentity.fromUUID(uuid) val signingEntity = KeyOwningIdentity.fromUUID(uuid)
log.debug { "Database lookup for public key ${key.toStringShort()}, found signing entity $signingEntity" } log.debug { "Database lookup for public key ${key.toStringShort()}, found signing entity $signingEntity" }
signingEntity signingEntity
} else { } else {
log.debug { "Attempted to find owning identity for public key ${key.toStringShort()}, but key is unknown to node" } log.debug { "Database lookup for public key ${key.toStringShort()}, using ${KeyOwningIdentity.UnmappedIdentity}" }
null KeyOwningIdentity.UnmappedIdentity
} }
} }
} }

View File

@ -114,9 +114,9 @@ class PublicKeyToOwningIdentityCacheImplTest {
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun `requesting a key unknown to the node returns null`() { fun `requesting a key unknown to the node returns unmapped identity`() {
val keys = generateKeyPair() val keys = generateKeyPair()
assertEquals(null, testCache[keys.public]) assertEquals(KeyOwningIdentity.UnmappedIdentity, testCache[keys.public])
} }
@Test(timeout=300_000) @Test(timeout=300_000)

View File

@ -13,8 +13,8 @@ class MockPublicKeyToOwningIdentityCache : WritablePublicKeyToOwningIdentityCach
private val cache: MutableMap<PublicKey, KeyOwningIdentity> = mutableMapOf<PublicKey, KeyOwningIdentity>().toSynchronised() private val cache: MutableMap<PublicKey, KeyOwningIdentity> = mutableMapOf<PublicKey, KeyOwningIdentity>().toSynchronised()
override fun get(key: PublicKey): KeyOwningIdentity? { override fun get(key: PublicKey): KeyOwningIdentity {
return cache[key] return cache[key] ?: KeyOwningIdentity.UnmappedIdentity
} }
override fun set(key: PublicKey, value: KeyOwningIdentity) { override fun set(key: PublicKey, value: KeyOwningIdentity) {