mirror of
https://github.com/corda/corda.git
synced 2024-12-21 13:57:54 +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.assertEquals
|
||||||
import kotlin.test.assertNotEquals
|
import kotlin.test.assertNotEquals
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
class CertificateRotationTest {
|
class CertificateRotationTest {
|
||||||
private val ref = OpaqueBytes.of(0x01)
|
private val ref = OpaqueBytes.of(0x01)
|
||||||
@ -180,7 +181,7 @@ class CertificateRotationTest {
|
|||||||
|
|
||||||
advertiseNodesToNetwork(mockNet.defaultNotaryNode, bob2, charlie)
|
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))
|
assertNull(charlie.services.identityService.wellKnownPartyFromX500Name(ALICE_NAME))
|
||||||
|
|
||||||
bob2.services.startFlow(CashPaymentFlow(1000.DOLLARS, charlie.party, false))
|
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.internal.schemas.NodeInfoSchemaV1
|
||||||
import net.corda.node.services.identity.PersistentIdentityService
|
import net.corda.node.services.identity.PersistentIdentityService
|
||||||
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
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.DBTransactionStorage
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
import net.corda.node.services.vault.NodeVaultService
|
import net.corda.node.services.vault.NodeVaultService
|
||||||
@ -133,7 +134,8 @@ object VaultMigrationSchemaV1 : MappedSchema(schemaFamily = VaultMigrationSchema
|
|||||||
PersistentIdentityService.PersistentPublicKeyHashToParty::class.java,
|
PersistentIdentityService.PersistentPublicKeyHashToParty::class.java,
|
||||||
BasicHSMKeyManagementService.PersistentKey::class.java,
|
BasicHSMKeyManagementService.PersistentKey::class.java,
|
||||||
NodeAttachmentService.DBAttachment::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
|
package net.corda.node.services.identity
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
import net.corda.core.identity.AbstractParty
|
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.api.IdentityServiceInternal
|
||||||
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
||||||
import net.corda.node.services.network.NotaryUpdateListener
|
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.PublicKeyHashToExternalId
|
||||||
import net.corda.node.services.persistence.WritablePublicKeyToOwningIdentityCache
|
import net.corda.node.services.persistence.WritablePublicKeyToOwningIdentityCache
|
||||||
import net.corda.node.utilities.AppendOnlyPersistentMap
|
import net.corda.node.utilities.AppendOnlyPersistentMap
|
||||||
@ -46,6 +48,8 @@ import java.security.cert.CollectionCertStoreParameters
|
|||||||
import java.security.cert.TrustAnchor
|
import java.security.cert.TrustAnchor
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.ExecutorService
|
||||||
|
import java.util.concurrent.Executors
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
import javax.annotation.concurrent.ThreadSafe
|
import javax.annotation.concurrent.ThreadSafe
|
||||||
import javax.persistence.Column
|
import javax.persistence.Column
|
||||||
@ -140,6 +144,8 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
|
|||||||
private fun mapToKey(party: PartyAndCertificate) = party.owningKey.toStringShort()
|
private fun mapToKey(party: PartyAndCertificate) = party.owningKey.toStringShort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val archiveIdentityExecutor: ExecutorService = Executors.newCachedThreadPool(ThreadFactoryBuilder().setNameFormat("archive-named-identity-thread-%d").build())
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}identities")
|
@javax.persistence.Table(name = "${NODE_DATABASE_PREFIX}identities")
|
||||||
class PersistentPublicKeyHashToCertificate(
|
class PersistentPublicKeyHashToCertificate(
|
||||||
@ -312,7 +318,76 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun wellKnownPartyFromX500Name(name: CordaX500Name): Party? = database.transaction {
|
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? {
|
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.node.services.PartyInfo
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.serialization.serialize
|
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.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
@ -34,6 +35,9 @@ import java.security.PublicKey
|
|||||||
import java.security.cert.CertPathValidatorException
|
import java.security.cert.CertPathValidatorException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.annotation.concurrent.ThreadSafe
|
import javax.annotation.concurrent.ThreadSafe
|
||||||
|
import javax.persistence.Column
|
||||||
|
import javax.persistence.Entity
|
||||||
|
import javax.persistence.Id
|
||||||
import javax.persistence.PersistenceException
|
import javax.persistence.PersistenceException
|
||||||
|
|
||||||
/** Database-based network map cache. */
|
/** Database-based network map cache. */
|
||||||
@ -61,6 +65,18 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
|
|||||||
@Volatile
|
@Volatile
|
||||||
private lateinit var rotatedNotaries: Set<CordaX500Name>
|
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.
|
// 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.
|
// Exclude duplicated entries, which are not present in the network map.
|
||||||
override val notaryIdentities: List<Party> get() = notaries.map { it.identity }
|
override val notaryIdentities: List<Party> get() = notaries.map { it.identity }
|
||||||
@ -294,6 +310,7 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
|
|||||||
synchronized(_changed) {
|
synchronized(_changed) {
|
||||||
database.transaction {
|
database.transaction {
|
||||||
removeInfoDB(session, node)
|
removeInfoDB(session, node)
|
||||||
|
archiveNamedIdentity(session, node)
|
||||||
changePublisher.onNext(MapChange.Removed(node))
|
changePublisher.onNext(MapChange.Removed(node))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,6 +319,16 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
|
|||||||
logger.debug { "Done removing node with info: $node" }
|
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>
|
override val allNodes: List<NodeInfo>
|
||||||
get() {
|
get() {
|
||||||
return database.transaction {
|
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.identity.PersistentIdentityService
|
||||||
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
import net.corda.node.services.keys.BasicHSMKeyManagementService
|
||||||
import net.corda.node.services.messaging.P2PMessageDeduplicator
|
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.DBCheckpointStorage
|
||||||
import net.corda.node.services.persistence.DBTransactionStorage
|
import net.corda.node.services.persistence.DBTransactionStorage
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
@ -49,7 +50,8 @@ class NodeSchemaService(private val extraSchemas: Set<MappedSchema> = emptySet()
|
|||||||
PersistentIdentityService.PersistentHashToPublicKey::class.java,
|
PersistentIdentityService.PersistentHashToPublicKey::class.java,
|
||||||
ContractUpgradeServiceImpl.DBContractUpgrade::class.java,
|
ContractUpgradeServiceImpl.DBContractUpgrade::class.java,
|
||||||
DBNetworkParametersStorage.PersistentNetworkParameters::class.java,
|
DBNetworkParametersStorage.PersistentNetworkParameters::class.java,
|
||||||
PublicKeyHashToExternalId::class.java
|
PublicKeyHashToExternalId::class.java,
|
||||||
|
PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java
|
||||||
)) {
|
)) {
|
||||||
override val migrationResource = "node-core.changelog-master"
|
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-v14-data.xml"/>
|
||||||
<include file="migration/node-core.changelog-v16.xml"/>
|
<include file="migration/node-core.changelog-v16.xml"/>
|
||||||
<include file="migration/node-core.changelog-v20.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. -->
|
<!-- This must run after node-core.changelog-init.xml, to prevent database columns being created twice. -->
|
||||||
<include file="migration/vault-schema.changelog-v9.xml"/>
|
<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)
|
@Column(name = "name", length = 128, nullable = false)
|
||||||
var name: String = "",
|
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 = ""
|
var publicKeyHash: String = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
package net.corda.node.services.network
|
package net.corda.node.services.network
|
||||||
|
|
||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.node.services.NetworkMapCache
|
import net.corda.core.node.services.NetworkMapCache
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.node.services.api.NetworkMapCacheInternal
|
import net.corda.node.services.api.NetworkMapCacheInternal
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.BOB_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.core.singleIdentity
|
||||||
import net.corda.testing.node.internal.InternalMockNetwork
|
import net.corda.testing.node.internal.InternalMockNetwork
|
||||||
import net.corda.testing.node.internal.InternalMockNodeParameters
|
import net.corda.testing.node.internal.InternalMockNodeParameters
|
||||||
|
import net.corda.testing.node.internal.TestStartedNode
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -18,6 +24,7 @@ import kotlin.test.assertNotNull
|
|||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
class NetworkMapCacheTest {
|
class NetworkMapCacheTest {
|
||||||
|
private val TestStartedNode.party get() = info.legalIdentities.first()
|
||||||
private val mockNet = InternalMockNetwork()
|
private val mockNet = InternalMockNetwork()
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@ -25,6 +32,153 @@ class NetworkMapCacheTest {
|
|||||||
mockNet.stopNodes()
|
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)
|
@Test(timeout=300_000)
|
||||||
fun `key collision`() {
|
fun `key collision`() {
|
||||||
val entropy = BigInteger.valueOf(24012017L)
|
val entropy = BigInteger.valueOf(24012017L)
|
||||||
|
Loading…
Reference in New Issue
Block a user