mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
ENT-6386: Revert change of behaviour in rpcOps.wellKnownPartyFromX500Name for revoked identity (#7032)
* ENT-6386: Reverting wellKnownPartyFromX500Name functionality to work … (#4347)
This commit is contained in:
parent
c05c1934cf
commit
b17e4571bf
@ -31,6 +31,7 @@ import java.security.PublicKey
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class CertificateRotationTest {
|
||||
private val ref = OpaqueBytes.of(0x01)
|
||||
@ -180,7 +181,7 @@ class CertificateRotationTest {
|
||||
|
||||
advertiseNodesToNetwork(mockNet.defaultNotaryNode, bob2, charlie)
|
||||
|
||||
assertNull(bob2.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME))
|
||||
assertNotNull(bob2.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME))
|
||||
assertNull(charlie.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME))
|
||||
|
||||
bob2.services.startFlow(CashPaymentFlow(1000.DOLLARS, charlie.party, false))
|
||||
|
@ -14,6 +14,7 @@ import net.corda.node.internal.DBNetworkParametersStorage
|
||||
import net.corda.node.internal.schemas.NodeInfoSchemaV1
|
||||
import net.corda.node.services.identity.PersistentIdentityService
|
||||
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
||||
import net.corda.node.services.network.PersistentNetworkMapCache
|
||||
import net.corda.node.services.persistence.DBTransactionStorage
|
||||
import net.corda.node.services.persistence.NodeAttachmentService
|
||||
import net.corda.node.services.vault.NodeVaultService
|
||||
@ -133,7 +134,8 @@ object VaultMigrationSchemaV1 : MappedSchema(schemaFamily = VaultMigrationSchema
|
||||
PersistentIdentityService.PersistentPublicKeyHashToParty::class.java,
|
||||
BasicHSMKeyManagementService.PersistentKey::class.java,
|
||||
NodeAttachmentService.DBAttachment::class.java,
|
||||
DBNetworkParametersStorage.PersistentNetworkParameters::class.java
|
||||
DBNetworkParametersStorage.PersistentNetworkParameters::class.java,
|
||||
PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.node.services.identity
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.identity.AbstractParty
|
||||
@ -22,6 +23,7 @@ import net.corda.node.internal.schemas.NodeInfoSchemaV1
|
||||
import net.corda.node.services.api.IdentityServiceInternal
|
||||
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
||||
import net.corda.node.services.network.NotaryUpdateListener
|
||||
import net.corda.node.services.network.PersistentNetworkMapCache
|
||||
import net.corda.node.services.persistence.PublicKeyHashToExternalId
|
||||
import net.corda.node.services.persistence.WritablePublicKeyToOwningIdentityCache
|
||||
import net.corda.node.utilities.AppendOnlyPersistentMap
|
||||
@ -46,6 +48,8 @@ import java.security.cert.CollectionCertStoreParameters
|
||||
import java.security.cert.TrustAnchor
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.stream.Stream
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
import javax.persistence.Column
|
||||
@ -140,6 +144,8 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
|
||||
private fun mapToKey(party: PartyAndCertificate) = party.owningKey.toStringShort()
|
||||
}
|
||||
|
||||
val archiveIdentityExecutor: ExecutorService = Executors.newCachedThreadPool(ThreadFactoryBuilder().setNameFormat("archive-named-identity-thread-%d").build())
|
||||
|
||||
@Entity
|
||||
@javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}identities")
|
||||
class PersistentPublicKeyHashToCertificate(
|
||||
@ -312,7 +318,76 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
|
||||
}
|
||||
|
||||
override fun wellKnownPartyFromX500Name(name: CordaX500Name): Party? = database.transaction {
|
||||
nameToParty[name]?.orElse(null)
|
||||
if (nameToParty[name]?.isPresent == true) {
|
||||
nameToParty[name]?.get()
|
||||
}
|
||||
else {
|
||||
retrievePartyFromArchive(name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun retrievePartyFromArchive(name: CordaX500Name): Party? {
|
||||
val hashKey = database.transaction {
|
||||
val query = session.criteriaBuilder.createQuery(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
val queryRoot = query.from(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
query.where(session.criteriaBuilder.equal(queryRoot.get<String>("name"), name.toString()))
|
||||
val resultList = session.createQuery(query).resultList
|
||||
if (resultList.isNotEmpty()) {
|
||||
resultList?.first()?.publicKeyHash
|
||||
}
|
||||
else {
|
||||
retrieveHashKeyAndCacheParty(name)
|
||||
}
|
||||
}
|
||||
return hashKey?.let { keyToPartyAndCert[it]?.party }
|
||||
}
|
||||
|
||||
private fun retrieveHashKeyAndCacheParty(name: CordaX500Name): String? {
|
||||
return database.transaction {
|
||||
val cb = session.criteriaBuilder
|
||||
val query = cb.createQuery(PersistentPublicKeyHashToParty::class.java)
|
||||
val root = query.from(PersistentPublicKeyHashToParty::class.java)
|
||||
val isNotConfidentialIdentity = cb.equal(root.get<String>("publicKeyHash"), root.get<String>("owningKeyHash"))
|
||||
val matchName = cb.equal(root.get<String>("name"), name.toString())
|
||||
query.select(root).where(cb.and(matchName, isNotConfidentialIdentity))
|
||||
val resultList = session.createQuery(query).resultList
|
||||
var hashKey: String? = if (resultList.isNotEmpty()) {
|
||||
if (resultList.size == 1) {
|
||||
resultList?.single()?.owningKeyHash
|
||||
}
|
||||
else {
|
||||
selectIdentityHash(session, resultList.mapNotNull { it.publicKeyHash }, name)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
archiveNamedIdentity(name.toString(), hashKey)
|
||||
hashKey
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectIdentityHash(session: Session, hashList: List<String>, name: CordaX500Name): String? {
|
||||
val cb = session.criteriaBuilder
|
||||
val query = cb.createQuery(PersistentPublicKeyHashToCertificate::class.java)
|
||||
val root = query.from(PersistentPublicKeyHashToCertificate::class.java)
|
||||
query.select(root).where(root.get<String>("publicKeyHash").`in`(hashList))
|
||||
val resultList = session.createQuery(query).resultList
|
||||
resultList.sortWith(compareBy { PartyAndCertificate(X509CertificateFactory().delegate.generateCertPath(it.identity.inputStream())).certificate.notBefore })
|
||||
log.warn("Retrieving identity hash for removed identity '${name}', more that one hash found, returning last one according to notBefore validity of certificate." +
|
||||
" Hash returned is ${resultList.last().publicKeyHash}")
|
||||
return resultList.last().publicKeyHash
|
||||
}
|
||||
|
||||
private fun archiveNamedIdentity(name:String, publicKeyHash: String?) {
|
||||
archiveIdentityExecutor.submit {
|
||||
database.transaction {
|
||||
val deleteQuery = session.criteriaBuilder.createCriteriaDelete(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
val queryRoot = deleteQuery.from(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
deleteQuery.where(session.criteriaBuilder.equal(queryRoot.get<String>("name"), name))
|
||||
session.createQuery(deleteQuery).executeUpdate()
|
||||
session.save(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash(name, publicKeyHash))
|
||||
}
|
||||
}.get()
|
||||
}
|
||||
|
||||
override fun wellKnownPartyFromAnonymous(party: AbstractParty): Party? {
|
||||
|
@ -17,6 +17,7 @@ import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||
import net.corda.core.node.services.PartyInfo
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.core.utilities.debug
|
||||
@ -34,6 +35,9 @@ import java.security.PublicKey
|
||||
import java.security.cert.CertPathValidatorException
|
||||
import java.util.*
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.Id
|
||||
import javax.persistence.PersistenceException
|
||||
|
||||
/** Database-based network map cache. */
|
||||
@ -61,6 +65,18 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
|
||||
@Volatile
|
||||
private lateinit var rotatedNotaries: Set<CordaX500Name>
|
||||
|
||||
@Entity
|
||||
@javax.persistence.Table(name = "node_named_identities")
|
||||
data class PersistentPartyToPublicKeyHash(
|
||||
@Id
|
||||
@Suppress("MagicNumber") // database column width
|
||||
@Column(name = "name", length = 128, nullable = false)
|
||||
var name: String = "",
|
||||
|
||||
@Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE, nullable = true)
|
||||
var publicKeyHash: String? = ""
|
||||
)
|
||||
|
||||
// Notary whitelist may contain multiple identities with the same X.500 name after certificate rotation.
|
||||
// Exclude duplicated entries, which are not present in the network map.
|
||||
override val notaryIdentities: List<Party> get() = notaries.map { it.identity }
|
||||
@ -294,6 +310,7 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
|
||||
synchronized(_changed) {
|
||||
database.transaction {
|
||||
removeInfoDB(session, node)
|
||||
archiveNamedIdentity(session, node)
|
||||
changePublisher.onNext(MapChange.Removed(node))
|
||||
}
|
||||
}
|
||||
@ -302,6 +319,16 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
|
||||
logger.debug { "Done removing node with info: $node" }
|
||||
}
|
||||
|
||||
private fun archiveNamedIdentity(session: Session, nodeInfo: NodeInfo) {
|
||||
nodeInfo.legalIdentities.forEach { party ->
|
||||
val deleteQuery = session.criteriaBuilder.createCriteriaDelete(PersistentPartyToPublicKeyHash::class.java)
|
||||
val queryRoot = deleteQuery.from(PersistentPartyToPublicKeyHash::class.java)
|
||||
deleteQuery.where(session.criteriaBuilder.equal(queryRoot.get<String>("name"), party.name.toString()))
|
||||
session.createQuery(deleteQuery).executeUpdate()
|
||||
session.save(PersistentPartyToPublicKeyHash(party.name.toString(), party.owningKey.toStringShort() ))
|
||||
}
|
||||
}
|
||||
|
||||
override val allNodes: List<NodeInfo>
|
||||
get() {
|
||||
return database.transaction {
|
||||
|
@ -14,6 +14,7 @@ import net.corda.node.services.events.NodeSchedulerService
|
||||
import net.corda.node.services.identity.PersistentIdentityService
|
||||
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
||||
import net.corda.node.services.messaging.P2PMessageDeduplicator
|
||||
import net.corda.node.services.network.PersistentNetworkMapCache
|
||||
import net.corda.node.services.persistence.DBCheckpointStorage
|
||||
import net.corda.node.services.persistence.DBTransactionStorage
|
||||
import net.corda.node.services.persistence.NodeAttachmentService
|
||||
@ -49,7 +50,8 @@ class NodeSchemaService(private val extraSchemas: Set<MappedSchema> = emptySet()
|
||||
PersistentIdentityService.PersistentHashToPublicKey::class.java,
|
||||
ContractUpgradeServiceImpl.DBContractUpgrade::class.java,
|
||||
DBNetworkParametersStorage.PersistentNetworkParameters::class.java,
|
||||
PublicKeyHashToExternalId::class.java
|
||||
PublicKeyHashToExternalId::class.java,
|
||||
PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java
|
||||
)) {
|
||||
override val migrationResource = "node-core.changelog-master"
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
<include file="migration/node-core.changelog-v14-data.xml"/>
|
||||
<include file="migration/node-core.changelog-v16.xml"/>
|
||||
<include file="migration/node-core.changelog-v20.xml"/>
|
||||
<include file="migration/node-core.changelog-v22.xml"/>
|
||||
|
||||
<!-- This must run after node-core.changelog-init.xml, to prevent database columns being created twice. -->
|
||||
<include file="migration/vault-schema.changelog-v9.xml"/>
|
||||
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
|
||||
<changeSet author="R3.Corda" id="add_node_named_identities_table_back_in">
|
||||
<createTable tableName="node_named_identities">
|
||||
<column name="name" type="NVARCHAR(128)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="pk_hash" type="NVARCHAR(130)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
@ -50,7 +50,7 @@ object IdentityTestSchemaV1 : MappedSchema(
|
||||
@Column(name = "name", length = 128, nullable = false)
|
||||
var name: String = "",
|
||||
|
||||
@Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE, nullable = false)
|
||||
@Column(name = "pk_hash", length = MAX_HASH_HEX_SIZE, nullable = true)
|
||||
var publicKeyHash: String = ""
|
||||
)
|
||||
|
||||
|
@ -1,16 +1,22 @@
|
||||
package net.corda.node.services.network
|
||||
|
||||
import net.corda.core.crypto.toStringShort
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.node.services.NetworkMapCache
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.node.services.api.NetworkMapCacheInternal
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.CHARLIE_NAME
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.node.internal.InternalMockNetwork
|
||||
import net.corda.testing.node.internal.InternalMockNodeParameters
|
||||
import net.corda.testing.node.internal.TestStartedNode
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.math.BigInteger
|
||||
import kotlin.test.assertEquals
|
||||
@ -18,6 +24,7 @@ import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class NetworkMapCacheTest {
|
||||
private val TestStartedNode.party get() = info.legalIdentities.first()
|
||||
private val mockNet = InternalMockNetwork()
|
||||
|
||||
@After
|
||||
@ -25,6 +32,153 @@ class NetworkMapCacheTest {
|
||||
mockNet.stopNodes()
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `unknown Party object gets recorded as null entry in node_named_identities table`() {
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
assertEquals(null, bobNode.services.identityService.wellKnownPartyFromX500Name(CHARLIE_NAME))
|
||||
bobNode.database.transaction {
|
||||
val cb = session.criteriaBuilder
|
||||
val query = cb.createQuery(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
val root = query.from(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
|
||||
val matchPublicKey = cb.isNull(root.get<String>("publicKeyHash"))
|
||||
val matchName = cb.equal(root.get<String>("name"), CHARLIE_NAME.toString())
|
||||
query.select(root).where(cb.and(matchName, matchPublicKey))
|
||||
|
||||
val resultList = session.createQuery(query).resultList
|
||||
assertEquals(1, resultList.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `check Party object can still be retrieved when not in node_named_identities table`() {
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bobCache: NetworkMapCache = bobNode.services.networkMapCache
|
||||
|
||||
val bobCacheInternal = bobCache as NetworkMapCacheInternal
|
||||
assertNotNull(bobCacheInternal)
|
||||
bobCache.removeNode(aliceNode.info)
|
||||
|
||||
val alicePubKeyHash = aliceNode.info.legalIdentities[0].owningKey.toStringShort()
|
||||
|
||||
// Remove node adds an entry to the PersistentPartyToPublicKeyHash, so for this test delete this entry.
|
||||
removeNodeFromNodeNamedIdentitiesTable(bobNode, alicePubKeyHash)
|
||||
assertEquals(aliceNode.party, bobNode.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME))
|
||||
assertEquals(1, queryNodeNamedIdentities(bobNode, ALICE_NAME, alicePubKeyHash).size)
|
||||
}
|
||||
|
||||
private fun removeNodeFromNodeNamedIdentitiesTable(node: TestStartedNode, publicKeyHashToRemove: String) {
|
||||
// Remove node adds an entry to the PersistentPartyToPublicKeyHash, so for this test delete this entry.
|
||||
node.database.transaction {
|
||||
val deleteQuery = session.criteriaBuilder.createCriteriaDelete(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
val queryRoot = deleteQuery.from(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
deleteQuery.where(session.criteriaBuilder.equal(queryRoot.get<String>("publicKeyHash"), publicKeyHashToRemove))
|
||||
session.createQuery(deleteQuery).executeUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun queryNodeNamedIdentities(node: TestStartedNode, party: CordaX500Name, publicKeyHash: String): List<PersistentNetworkMapCache.PersistentPartyToPublicKeyHash> {
|
||||
return node.database.transaction {
|
||||
val cb = session.criteriaBuilder
|
||||
val query = cb.createQuery(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
val root = query.from(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java)
|
||||
val matchPublicKeyHash = cb.equal(root.get<String>("publicKeyHash"), publicKeyHash)
|
||||
val matchName = cb.equal(root.get<String>("name"), party.toString())
|
||||
query.select(root).where(cb.and(matchName, matchPublicKeyHash))
|
||||
session.createQuery(query).resultList
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `check removed node is inserted into node_name_identities table and then its Party object can be retrieved`() {
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bobCache: NetworkMapCache = bobNode.services.networkMapCache
|
||||
|
||||
val bobCacheInternal = bobCache as NetworkMapCacheInternal
|
||||
assertNotNull(bobCacheInternal)
|
||||
|
||||
val aliceParty1 = bobNode.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME)
|
||||
println("alicePart1 = $aliceParty1")
|
||||
bobCache.removeNode(aliceNode.info)
|
||||
|
||||
val alicePubKeyHash = aliceNode.info.legalIdentities[0].owningKey.toStringShort()
|
||||
assertEquals(1, queryNodeNamedIdentities(bobNode, ALICE_NAME, alicePubKeyHash).size)
|
||||
assertEquals(aliceNode.party, bobNode.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME))
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `check two removed nodes are both archived and then both Party objects are retrievable`() {
|
||||
val aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val charlieNode = mockNet.createPartyNode(CHARLIE_NAME)
|
||||
val bobCache: NetworkMapCache = bobNode.services.networkMapCache
|
||||
|
||||
val bobCacheInternal = bobCache as NetworkMapCacheInternal
|
||||
assertNotNull(bobCacheInternal)
|
||||
bobCache.removeNode(aliceNode.info)
|
||||
bobCache.removeNode(charlieNode.info)
|
||||
|
||||
val alicePubKeyHash = aliceNode.info.legalIdentities[0].owningKey.toStringShort()
|
||||
val charliePubKeyHash = charlieNode.info.legalIdentities[0].owningKey.toStringShort()
|
||||
assertEquals(1, queryNodeNamedIdentities(bobNode, ALICE_NAME, alicePubKeyHash).size)
|
||||
assertEquals(1, queryNodeNamedIdentities(bobNode, CHARLIE_NAME, charliePubKeyHash).size)
|
||||
assertEquals(aliceNode.party, bobNode.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME))
|
||||
assertEquals(charlieNode.party, bobNode.services.identityService.wellKnownPartyFromX500Name(CHARLIE_NAME))
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `check latest identity returned according to certificate after identity mock rotatated`() {
|
||||
val aliceNode1 = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bobCache: NetworkMapCache = bobNode.services.networkMapCache
|
||||
val alicePubKeyHash1 = aliceNode1.info.legalIdentities[0].owningKey.toStringShort()
|
||||
val bobCacheInternal = bobCache as NetworkMapCacheInternal
|
||||
assertNotNull(bobCacheInternal)
|
||||
bobCache.removeNode(aliceNode1.info)
|
||||
// Remove node adds an entry to the PersistentPartyToPublicKeyHash, so for this test delete this entry.
|
||||
removeNodeFromNodeNamedIdentitiesTable(bobNode, alicePubKeyHash1)
|
||||
val aliceNode2 = mockNet.createPartyNode(ALICE_NAME)
|
||||
val alicePubKeyHash2 = aliceNode2.info.legalIdentities[0].owningKey.toStringShort()
|
||||
bobCache.removeNode(aliceNode2.info)
|
||||
// Remove node adds an entry to the PersistentPartyToPublicKeyHash, so for this test delete this entry.
|
||||
removeNodeFromNodeNamedIdentitiesTable(bobNode, alicePubKeyHash2)
|
||||
val retrievedParty = bobNode.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME)
|
||||
// For both identity certificates the valid from date is the start of the day, so either could be returned.
|
||||
assertTrue(aliceNode2.party == retrievedParty || aliceNode1.party == retrievedParty)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `latest identity is archived after identity rotated`() {
|
||||
var aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
val bobNode = mockNet.createPartyNode(BOB_NAME)
|
||||
val bobCache: NetworkMapCache = bobNode.services.networkMapCache
|
||||
|
||||
val bobCacheInternal = bobCache as NetworkMapCacheInternal
|
||||
assertNotNull(bobCacheInternal)
|
||||
bobCache.removeNode(aliceNode.info)
|
||||
|
||||
fun checkArchivedIdentity(bobNode: TestStartedNode, aliceNode: TestStartedNode) {
|
||||
val alicePubKeyHash = aliceNode.info.legalIdentities[0].owningKey.toStringShort()
|
||||
bobNode.database.transaction {
|
||||
val hashToIdentityStatement = database.dataSource.connection.prepareStatement("SELECT name, pk_hash FROM node_named_identities WHERE pk_hash=?")
|
||||
hashToIdentityStatement.setString(1, alicePubKeyHash)
|
||||
val aliceResultSet = hashToIdentityStatement.executeQuery()
|
||||
|
||||
Assert.assertTrue(aliceResultSet.next())
|
||||
Assert.assertEquals(ALICE_NAME.toString(), aliceResultSet.getString("name"))
|
||||
Assert.assertEquals(alicePubKeyHash.toString(), aliceResultSet.getString("pk_hash"))
|
||||
Assert.assertFalse(aliceResultSet.next())
|
||||
}
|
||||
}
|
||||
checkArchivedIdentity(bobNode, aliceNode)
|
||||
aliceNode.dispose()
|
||||
aliceNode = mockNet.createPartyNode(ALICE_NAME)
|
||||
bobCache.removeNode(aliceNode.info)
|
||||
checkArchivedIdentity(bobNode, aliceNode)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `key collision`() {
|
||||
val entropy = BigInteger.valueOf(24012017L)
|
||||
|
Loading…
Reference in New Issue
Block a user