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.
*
* 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 {
log.info("Linking: ${publicKey.hash} to ${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? {
return _pkToIdCache[publicKey]?.uuid
return _pkToIdCache[publicKey].uuid
}
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.utilities.contextLogger
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.persistence.CordaPersistence
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
@ -22,42 +19,10 @@ class PublicKeyToOwningIdentityCacheImpl(private val database: CordaPersistence,
val log = contextLogger()
}
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())
private val cache = cacheFactory.buildNamed<PublicKey, KeyOwningIdentity>(
Caffeine.newBuilder(),
"PublicKeyToOwningIdentityCache_cache"
)
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.
@ -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
* 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) {
database.transaction {
val criteriaBuilder = session.criteriaBuilder
val criteriaQuery = criteriaBuilder.createQuery(UUID::class.java)
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 uuid = session.find(PublicKeyHashToExternalId::class.java, key.toStringShort())?.externalId
if (uuid != null) {
val signingEntity = KeyOwningIdentity.fromUUID(uuid)
log.debug { "Database lookup for public key ${key.toStringShort()}, found signing entity $signingEntity" }
signingEntity
} else {
log.debug { "Attempted to find owning identity for public key ${key.toStringShort()}, but key is unknown to node" }
null
log.debug { "Database lookup for public key ${key.toStringShort()}, using ${KeyOwningIdentity.UnmappedIdentity}" }
KeyOwningIdentity.UnmappedIdentity
}
}
}

View File

@ -114,9 +114,9 @@ class PublicKeyToOwningIdentityCacheImplTest {
}
@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()
assertEquals(null, testCache[keys.public])
assertEquals(KeyOwningIdentity.UnmappedIdentity, testCache[keys.public])
}
@Test(timeout=300_000)

View File

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