mirror of
https://github.com/corda/corda.git
synced 2025-06-18 15:18:16 +00:00
Network Map signing (#87)
* Network Map signing * Fixing failing tests * Fixing integration tests * Addressing review comments * Addressing review comments * Rebasing to the new network parameters + network map ownership redesign * Addressing review comments * Addressing review comments * Splitting the PR * Reverting enum uppercasing * Fixing the NetworkMapEntity comment * Addressing review comments - round 3 * Fixing docs and adding some TODOS * Removing nullification of the common name
This commit is contained in:
@ -0,0 +1,96 @@
|
||||
package com.r3.corda.networkmanage
|
||||
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateData
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequest
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
||||
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateDataEntity
|
||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.NetworkParameters
|
||||
import net.corda.core.node.NotaryInfo
|
||||
import net.corda.core.utilities.seconds
|
||||
import net.corda.testing.SerializationEnvironmentRule
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||
import org.junit.Rule
|
||||
import java.security.cert.CertPath
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
abstract class TestBase {
|
||||
@Rule
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule()
|
||||
|
||||
protected fun certificateSigningRequestEntity(
|
||||
requestId: String = SecureHash.randomSHA256().toString(),
|
||||
status: RequestStatus = RequestStatus.New,
|
||||
legalName: String = "TestLegalName",
|
||||
modifiedBy: List<String> = emptyList(),
|
||||
modifiedAt: Instant = Instant.now(),
|
||||
remark: String = "Test remark",
|
||||
certificateData: CertificateDataEntity? = null,
|
||||
requestBytes: ByteArray = ByteArray(0)
|
||||
): CertificateSigningRequestEntity {
|
||||
return CertificateSigningRequestEntity(
|
||||
requestId = requestId,
|
||||
status = status,
|
||||
legalName = legalName,
|
||||
modifiedBy = modifiedBy,
|
||||
modifiedAt = modifiedAt,
|
||||
remark = remark,
|
||||
certificateData = certificateData,
|
||||
requestBytes = requestBytes
|
||||
)
|
||||
}
|
||||
|
||||
protected fun certificateSigningRequest(
|
||||
requestId: String = SecureHash.randomSHA256().toString(),
|
||||
status: RequestStatus = RequestStatus.New,
|
||||
legalName: String = "TestLegalName",
|
||||
remark: String = "Test remark",
|
||||
request: PKCS10CertificationRequest = mock(),
|
||||
certData: CertificateData = mock(),
|
||||
modifiedBy: List<String> = emptyList()
|
||||
): CertificateSigningRequest {
|
||||
return CertificateSigningRequest(
|
||||
requestId = requestId,
|
||||
status = status,
|
||||
legalName = legalName,
|
||||
remark = remark,
|
||||
certData = certData,
|
||||
request = request,
|
||||
modifiedBy = modifiedBy
|
||||
)
|
||||
}
|
||||
|
||||
protected fun certificateData(publicKeyHash: String = SecureHash.randomSHA256().toString(),
|
||||
certStatus: CertificateStatus = CertificateStatus.VALID,
|
||||
certPath: CertPath = mock()): CertificateData {
|
||||
return CertificateData(
|
||||
publicKeyHash = publicKeyHash,
|
||||
certStatus = certStatus,
|
||||
certPath = certPath
|
||||
)
|
||||
}
|
||||
|
||||
// TODO remove this once testNetworkParameters are updated with default parameters
|
||||
protected fun createNetworkParameters(minimumPlatformVersion: Int = 1,
|
||||
notaries: List<NotaryInfo> = emptyList(),
|
||||
eventHorizon: Duration = 1.seconds,
|
||||
maxMessageSize: Int = 0,
|
||||
maxTransactionSize: Int = 0,
|
||||
modifiedTime: Instant = Instant.now(),
|
||||
epoch: Int = 1): NetworkParameters {
|
||||
return NetworkParameters(
|
||||
minimumPlatformVersion = minimumPlatformVersion,
|
||||
notaries = notaries,
|
||||
eventHorizon = eventHorizon,
|
||||
maxMessageSize = maxMessageSize,
|
||||
maxTransactionSize = maxTransactionSize,
|
||||
modifiedTime = modifiedTime,
|
||||
epoch = epoch
|
||||
)
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package com.r3.corda.networkmanage.common.persistence
|
||||
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage.Companion.DOORMAN_SIGNATURE
|
||||
import com.r3.corda.networkmanage.common.persistence.entity.CertificateSigningRequestEntity
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import net.corda.core.crypto.Crypto
|
||||
@ -22,14 +24,14 @@ import java.security.KeyPair
|
||||
import java.util.*
|
||||
import kotlin.test.*
|
||||
|
||||
class DBCertificateRequestStorageTest {
|
||||
private lateinit var storage: DBCertificateRequestStorage
|
||||
class DBCertificateRequestStorageTest : TestBase() {
|
||||
private lateinit var storage: PersistentCertificateRequestStorage
|
||||
private lateinit var persistence: CordaPersistence
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
persistence = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), { throw UnsupportedOperationException() }, SchemaService())
|
||||
storage = DBCertificateRequestStorage(persistence)
|
||||
storage = PersistentCertificateRequestStorage(persistence)
|
||||
}
|
||||
|
||||
@After
|
||||
@ -42,7 +44,7 @@ class DBCertificateRequestStorageTest {
|
||||
val request = createRequest("LegalName").first
|
||||
val requestId = storage.saveRequest(request)
|
||||
assertNotNull(storage.getRequest(requestId)).apply {
|
||||
assertEquals(request, PKCS10CertificationRequest(this.request))
|
||||
assertEquals(request, this.request)
|
||||
}
|
||||
assertThat(storage.getRequests(RequestStatus.New).map { it.requestId }).containsOnly(requestId)
|
||||
}
|
||||
@ -55,11 +57,9 @@ class DBCertificateRequestStorageTest {
|
||||
// Pending request should equals to 1.
|
||||
assertEquals(1, storage.getRequests(RequestStatus.New).size)
|
||||
// Certificate should be empty.
|
||||
assertNull(storage.getRequest(requestId)!!.certificateData)
|
||||
assertNull(storage.getRequest(requestId)!!.certData)
|
||||
// Store certificate to DB.
|
||||
val result = storage.approveRequest(requestId, DOORMAN_SIGNATURE)
|
||||
// Check request request has been approved
|
||||
assertTrue(result)
|
||||
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
|
||||
// Check request is not ready yet.
|
||||
// assertTrue(storage.getResponse(requestId) is CertificateResponse.NotReady)
|
||||
// New request should be empty.
|
||||
@ -72,12 +72,17 @@ class DBCertificateRequestStorageTest {
|
||||
val (request, _) = createRequest("LegalName")
|
||||
// Add request to DB.
|
||||
val requestId = storage.saveRequest(request)
|
||||
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
|
||||
storage.approveRequest(requestId, "ApproverA")
|
||||
|
||||
var thrown: Exception? = null
|
||||
// When subsequent approval is performed
|
||||
val result = storage.approveRequest(requestId, DOORMAN_SIGNATURE)
|
||||
try {
|
||||
storage.approveRequest(requestId, "ApproverB")
|
||||
} catch (e: IllegalArgumentException) {
|
||||
thrown = e
|
||||
}
|
||||
// Then check request has not been approved
|
||||
assertFalse(result)
|
||||
assertNotNull(thrown)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -88,7 +93,7 @@ class DBCertificateRequestStorageTest {
|
||||
// New request should equals to 1.
|
||||
assertEquals(1, storage.getRequests(RequestStatus.New).size)
|
||||
// Certificate should be empty.
|
||||
assertNull(storage.getRequest(requestId)!!.certificateData)
|
||||
assertNull(storage.getRequest(requestId)!!.certData)
|
||||
// Store certificate to DB.
|
||||
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
|
||||
// Check request is not ready yet.
|
||||
@ -105,7 +110,7 @@ class DBCertificateRequestStorageTest {
|
||||
buildCertPath(ourCertificate, intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
}, listOf(DOORMAN_SIGNATURE))
|
||||
// Check request is ready
|
||||
assertNotNull(storage.getRequest(requestId)!!.certificateData)
|
||||
assertNotNull(storage.getRequest(requestId)!!.certData)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -188,21 +193,15 @@ class DBCertificateRequestStorageTest {
|
||||
// then
|
||||
persistence.transaction {
|
||||
val auditReader = AuditReaderFactory.get(persistence.entityManagerFactory.createEntityManager())
|
||||
val newRevision = auditReader.find(CertificateSigningRequest::class.java, requestId, 1)
|
||||
val newRevision = auditReader.find(CertificateSigningRequestEntity::class.java, requestId, 1)
|
||||
assertEquals(RequestStatus.New, newRevision.status)
|
||||
assertTrue(newRevision.modifiedBy.isEmpty())
|
||||
val approvedRevision = auditReader.find(CertificateSigningRequest::class.java, requestId, 2)
|
||||
val approvedRevision = auditReader.find(CertificateSigningRequestEntity::class.java, requestId, 2)
|
||||
assertEquals(RequestStatus.Approved, approvedRevision.status)
|
||||
assertEquals(approver, approvedRevision.modifiedBy.first())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRequest(legalName: String): Pair<PKCS10CertificationRequest, KeyPair> {
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(organisation = legalName, locality = "London", country = "GB"), "my@mail.com", keyPair)
|
||||
return Pair(request, keyPair)
|
||||
}
|
||||
|
||||
private fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
||||
val props = Properties()
|
||||
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
||||
@ -221,3 +220,9 @@ class DBCertificateRequestStorageTest {
|
||||
return props
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createRequest(organisation: String): Pair<PKCS10CertificationRequest, KeyPair> {
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val request = X509Utilities.createCertificateSigningRequest(CordaX500Name(organisation = organisation, locality = "London", country = "GB"), "my@mail.com", keyPair)
|
||||
return Pair(request, keyPair)
|
||||
}
|
||||
|
@ -0,0 +1,164 @@
|
||||
package com.r3.corda.networkmanage.common.persistence
|
||||
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.signer.NetworkMap
|
||||
import com.r3.corda.networkmanage.common.signer.SignatureAndCertPath
|
||||
import com.r3.corda.networkmanage.common.signer.SignedNetworkMap
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.NotaryInfo
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.node.utilities.CertificateType
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.node.utilities.X509Utilities
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class DBNetworkMapStorageTest : TestBase() {
|
||||
private lateinit var networkMapStorage: NetworkMapStorage
|
||||
private lateinit var requestStorage: CertificationRequestStorage
|
||||
private lateinit var nodeInfoStorage: NodeInfoStorage
|
||||
private lateinit var persistence: CordaPersistence
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, CordaX500Name(commonName = "Corda Node Intermediate CA", locality = "London", organisation = "R3 LTD", country = "GB"), intermediateCAKey.public)
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
persistence = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), { throw UnsupportedOperationException() }, SchemaService())
|
||||
networkMapStorage = PersistentNetworkMapStorage(persistence)
|
||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||
requestStorage = PersistentCertificateRequestStorage(persistence)
|
||||
}
|
||||
|
||||
@After
|
||||
fun closeDb() {
|
||||
persistence.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `signNetworkMap creates current network map`() {
|
||||
// given
|
||||
// Create node info.
|
||||
val organisation = "Test"
|
||||
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
||||
requestStorage.approveRequest(requestId, "TestUser")
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisation, locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestId, certPath, emptyList())
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfo)
|
||||
// Some random bytes
|
||||
val signature = keyPair.sign(nodeInfo.serialize())
|
||||
nodeInfoStorage.signNodeInfo(nodeInfoHash, signature)
|
||||
|
||||
// Create network parameters
|
||||
val networkParametersHash = networkMapStorage.putNetworkParameters(testNetworkParameters(emptyList<NotaryInfo>()))
|
||||
|
||||
val signatureData = SignatureAndCertPath(signature, certPath)
|
||||
val signedNetworkMap = SignedNetworkMap(NetworkMap(listOf(nodeInfoHash.toString()), networkParametersHash.toString()), signatureData)
|
||||
|
||||
// when
|
||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||
|
||||
// then
|
||||
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
||||
assertEquals(signedNetworkMap, persistedSignedNetworkMap)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getLatestNetworkParameters returns last inserted`() {
|
||||
// given
|
||||
networkMapStorage.putNetworkParameters(createNetworkParameters(minimumPlatformVersion = 1))
|
||||
networkMapStorage.putNetworkParameters(createNetworkParameters(minimumPlatformVersion = 2))
|
||||
|
||||
// when
|
||||
val latest = networkMapStorage.getLatestNetworkParameters()
|
||||
|
||||
// then
|
||||
assertEquals(2, latest.minimumPlatformVersion)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getCurrentNetworkParameters returns current network map parameters`() {
|
||||
// given
|
||||
// Create network parameters
|
||||
val networkMapParametersHash = networkMapStorage.putNetworkParameters(createNetworkParameters(1))
|
||||
// Create empty network map
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val intermediateCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Corda", locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(intermediateCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
|
||||
// Sign network map making it current network map
|
||||
val hashedNetworkMap = NetworkMap(emptyList(), networkMapParametersHash.toString())
|
||||
val signatureData = SignatureAndCertPath(keyPair.sign(hashedNetworkMap.serialize()), certPath)
|
||||
val signedNetworkMap = SignedNetworkMap(hashedNetworkMap, signatureData)
|
||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||
|
||||
// Create new network parameters
|
||||
networkMapStorage.putNetworkParameters(createNetworkParameters(2))
|
||||
|
||||
// when
|
||||
val result = networkMapStorage.getCurrentNetworkParameters()
|
||||
|
||||
// then
|
||||
assertEquals(1, result.minimumPlatformVersion)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getDetachedSignedAndValidNodeInfoHashes returns only valid and signed node info hashes`() {
|
||||
// given
|
||||
// Create node info.
|
||||
val organisationA = "TestA"
|
||||
val requestIdA = requestStorage.saveRequest(createRequest(organisationA).first)
|
||||
requestStorage.approveRequest(requestIdA, "TestUser")
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCertA = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationA, locality = "London", country = "GB"), keyPair.public)
|
||||
val certPathA = buildCertPath(clientCertA.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestIdA, certPathA, emptyList())
|
||||
val organisationB = "TestB"
|
||||
val requestIdB = requestStorage.saveRequest(createRequest(organisationB).first)
|
||||
requestStorage.approveRequest(requestIdB, "TestUser")
|
||||
val clientCertB = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationB, locality = "London", country = "GB"), Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME).public)
|
||||
val certPathB = buildCertPath(clientCertB.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestIdB, certPathB, emptyList())
|
||||
val nodeInfoA = NodeInfo(listOf(NetworkHostAndPort("my.companyA.com", 1234)), listOf(PartyAndCertificate(certPathA)), 1, serial = 1L)
|
||||
val nodeInfoB = NodeInfo(listOf(NetworkHostAndPort("my.companyB.com", 1234)), listOf(PartyAndCertificate(certPathB)), 1, serial = 1L)
|
||||
val nodeInfoHashA = nodeInfoStorage.putNodeInfo(nodeInfoA)
|
||||
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(nodeInfoB)
|
||||
// Sign node info
|
||||
nodeInfoStorage.signNodeInfo(nodeInfoHashA, keyPair.sign(nodeInfoA.serialize()))
|
||||
nodeInfoStorage.signNodeInfo(nodeInfoHashB, keyPair.sign(nodeInfoB.serialize()))
|
||||
|
||||
// Create network parameters
|
||||
val networkParametersHash = networkMapStorage.putNetworkParameters(createNetworkParameters())
|
||||
val networkMap = NetworkMap(listOf(nodeInfoHashA.toString()), networkParametersHash.toString())
|
||||
val signatureData = SignatureAndCertPath(keyPair.sign(networkMap.serialize()), certPathA)
|
||||
val signedNetworkMap = SignedNetworkMap(networkMap, signatureData)
|
||||
|
||||
// Sign network map
|
||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||
|
||||
// when
|
||||
val detachedHashes = networkMapStorage.getDetachedSignedAndValidNodeInfoHashes()
|
||||
|
||||
// then
|
||||
assertEquals(1, detachedHashes.size)
|
||||
assertTrue(detachedHashes.contains(nodeInfoHashB))
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
package com.r3.corda.networkmanage.common.persistence
|
||||
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage.Companion.DOORMAN_SIGNATURE
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.serialization.SerializationDefaults
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.node.serialization.KryoServerSerializationScheme
|
||||
import net.corda.node.utilities.CertificateType
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.node.utilities.X509Utilities
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.nodeapi.internal.serialization.*
|
||||
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class PersistenceNodeInfoStorageTest {
|
||||
private lateinit var nodeInfoStorage: NodeInfoStorage
|
||||
private lateinit var requestStorage: CertificationRequestStorage
|
||||
private lateinit var persistence: CordaPersistence
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, CordaX500Name(commonName = "Corda Node Intermediate CA", locality = "London", organisation = "R3 LTD", country = "GB"), intermediateCAKey.public)
|
||||
|
||||
companion object {
|
||||
@BeforeClass
|
||||
@JvmStatic
|
||||
fun initSerialization() {
|
||||
try {
|
||||
SerializationDefaults.SERIALIZATION_FACTORY = SerializationFactoryImpl().apply {
|
||||
registerScheme(KryoServerSerializationScheme())
|
||||
registerScheme(AMQPServerSerializationScheme())
|
||||
}
|
||||
SerializationDefaults.P2P_CONTEXT = KRYO_P2P_CONTEXT
|
||||
SerializationDefaults.RPC_SERVER_CONTEXT = KRYO_RPC_SERVER_CONTEXT
|
||||
SerializationDefaults.STORAGE_CONTEXT = KRYO_STORAGE_CONTEXT
|
||||
SerializationDefaults.CHECKPOINT_CONTEXT = KRYO_CHECKPOINT_CONTEXT
|
||||
} catch (ignored: Exception) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
persistence = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), { throw UnsupportedOperationException() }, SchemaService())
|
||||
nodeInfoStorage = PersistenceNodeInfoStorage(persistence)
|
||||
requestStorage = DBCertificateRequestStorage(persistence)
|
||||
}
|
||||
|
||||
@After
|
||||
fun closeDb() {
|
||||
persistence.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test get CertificatePath`() {
|
||||
// Create node info.
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
|
||||
val request = X509Utilities.createCertificateSigningRequest(nodeInfo.legalIdentities.first().name, "my@mail.com", keyPair)
|
||||
|
||||
val requestId = requestStorage.saveRequest(request)
|
||||
requestStorage.approveRequest(requestId, DOORMAN_SIGNATURE)
|
||||
|
||||
assertNull(nodeInfoStorage.getCertificatePath(keyPair.public.hash()))
|
||||
|
||||
requestStorage.putCertificatePath(requestId, buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()), listOf(DOORMAN_SIGNATURE))
|
||||
|
||||
val storedCertPath = nodeInfoStorage.getCertificatePath(keyPair.public.hash())
|
||||
assertNotNull(storedCertPath)
|
||||
|
||||
assertEquals(clientCert.toX509Certificate(), storedCertPath!!.certificates.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test getNodeInfoHashes`() {
|
||||
// Create node info.
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val clientCert2 = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME).public)
|
||||
val certPath2 = buildCertPath(clientCert2.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfoSame = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfo2 = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath2)), 1, serial = 1L)
|
||||
|
||||
nodeInfoStorage.putNodeInfo(nodeInfo)
|
||||
nodeInfoStorage.putNodeInfo(nodeInfoSame)
|
||||
|
||||
// getNodeInfoHashes should contain 1 hash.
|
||||
assertEquals(listOf(nodeInfo.serialize().sha256().toString()), nodeInfoStorage.getNodeInfoHashes())
|
||||
|
||||
nodeInfoStorage.putNodeInfo(nodeInfo2)
|
||||
// getNodeInfoHashes should contain 2 hash.
|
||||
assertEquals(listOf(nodeInfo2.serialize().sha256().toString(), nodeInfo.serialize().sha256().toString()).sorted(), nodeInfoStorage.getNodeInfoHashes().sorted())
|
||||
|
||||
// Test retrieve NodeInfo.
|
||||
assertEquals(nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256().toString()))
|
||||
assertEquals(nodeInfo2, nodeInfoStorage.getNodeInfo(nodeInfo2.serialize().sha256().toString()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `same pub key with different node info`() {
|
||||
// Create node info.
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfoSamePubKey = NodeInfo(listOf(NetworkHostAndPort("my.company2.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
|
||||
nodeInfoStorage.putNodeInfo(nodeInfo)
|
||||
assertEquals(nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256().toString()))
|
||||
|
||||
// This should replace the node info.
|
||||
nodeInfoStorage.putNodeInfo(nodeInfoSamePubKey)
|
||||
// Old node info should be removed.
|
||||
assertNull(nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256().toString()))
|
||||
assertEquals(nodeInfoSamePubKey, nodeInfoStorage.getNodeInfo(nodeInfoSamePubKey.serialize().sha256().toString()))
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package com.r3.corda.networkmanage.common.persistence
|
||||
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.hashString
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.crypto.sign
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.node.utilities.CertificateType
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.node.utilities.X509Utilities
|
||||
import net.corda.node.utilities.configureDatabase
|
||||
import net.corda.testing.node.MockServices
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class PersitenceNodeInfoStorageTest : TestBase() {
|
||||
private lateinit var requestStorage: CertificationRequestStorage
|
||||
private lateinit var nodeInfoStorage: NodeInfoStorage
|
||||
private lateinit var persistence: CordaPersistence
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 LTD", country = "GB"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, CordaX500Name(commonName = "Corda Node Intermediate CA", locality = "London", organisation = "R3 LTD", country = "GB"), intermediateCAKey.public)
|
||||
|
||||
@Before
|
||||
fun startDb() {
|
||||
persistence = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), { throw UnsupportedOperationException() }, SchemaService())
|
||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||
requestStorage = PersistentCertificateRequestStorage(persistence)
|
||||
}
|
||||
|
||||
@After
|
||||
fun closeDb() {
|
||||
persistence.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test get CertificatePath`() {
|
||||
// Create node info.
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = "Test", locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
|
||||
val request = X509Utilities.createCertificateSigningRequest(nodeInfo.legalIdentities.first().name, "my@mail.com", keyPair)
|
||||
|
||||
val requestId = requestStorage.saveRequest(request)
|
||||
requestStorage.approveRequest(requestId, CertificationRequestStorage.DOORMAN_SIGNATURE)
|
||||
|
||||
assertNull(nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString())))
|
||||
|
||||
requestStorage.putCertificatePath(requestId, buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate()), listOf(CertificationRequestStorage.DOORMAN_SIGNATURE))
|
||||
|
||||
val storedCertPath = nodeInfoStorage.getCertificatePath(SecureHash.parse(keyPair.public.hashString()))
|
||||
assertNotNull(storedCertPath)
|
||||
|
||||
assertEquals(clientCert.toX509Certificate(), storedCertPath!!.certificates.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test getNodeInfoHashes`() {
|
||||
// Create node info.
|
||||
val organisationA = "TestA"
|
||||
val requestIdA = requestStorage.saveRequest(createRequest(organisationA).first)
|
||||
requestStorage.approveRequest(requestIdA, "TestUser")
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCertA = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationA, locality = "London", country = "GB"), keyPair.public)
|
||||
val certPathA = buildCertPath(clientCertA.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestIdA, certPathA, emptyList())
|
||||
val organisationB = "TestB"
|
||||
val requestIdB = requestStorage.saveRequest(createRequest(organisationB).first)
|
||||
requestStorage.approveRequest(requestIdB, "TestUser")
|
||||
val clientCertB = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisationB, locality = "London", country = "GB"), Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME).public)
|
||||
val certPathB = buildCertPath(clientCertB.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestIdB, certPathB, emptyList())
|
||||
val nodeInfoA = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPathA)), 1, serial = 1L)
|
||||
val nodeInfoSame = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPathA)), 1, serial = 1L)
|
||||
val nodeInfoB = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPathB)), 1, serial = 1L)
|
||||
|
||||
nodeInfoStorage.putNodeInfo(nodeInfoA)
|
||||
nodeInfoStorage.putNodeInfo(nodeInfoSame)
|
||||
|
||||
// getNodeInfoHashes should contain 1 hash.
|
||||
assertEquals(listOf(nodeInfoA.serialize().sha256()), nodeInfoStorage.getUnsignedNodeInfoHashes())
|
||||
|
||||
nodeInfoStorage.putNodeInfo(nodeInfoB)
|
||||
// getNodeInfoHashes should contain 2 hash.
|
||||
assertEquals(listOf(nodeInfoB.serialize().sha256(), nodeInfoA.serialize().sha256()).sorted(), nodeInfoStorage.getUnsignedNodeInfoHashes().sorted())
|
||||
|
||||
// Test retrieve NodeInfo.
|
||||
assertEquals(nodeInfoA, nodeInfoStorage.getNodeInfo(nodeInfoA.serialize().sha256()))
|
||||
assertEquals(nodeInfoB, nodeInfoStorage.getNodeInfo(nodeInfoB.serialize().sha256()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `same pub key with different node info`() {
|
||||
// Create node info.
|
||||
val organisation = "Test"
|
||||
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
||||
requestStorage.approveRequest(requestId, "TestUser")
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisation, locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestId, certPath, emptyList())
|
||||
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfoSamePubKey = NodeInfo(listOf(NetworkHostAndPort("my.company2.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
|
||||
nodeInfoStorage.putNodeInfo(nodeInfo)
|
||||
assertEquals(nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256()))
|
||||
|
||||
// This should replace the node info.
|
||||
nodeInfoStorage.putNodeInfo(nodeInfoSamePubKey)
|
||||
// Old node info should be removed.
|
||||
assertNull(nodeInfoStorage.getNodeInfo(nodeInfo.serialize().sha256()))
|
||||
assertEquals(nodeInfoSamePubKey, nodeInfoStorage.getNodeInfo(nodeInfoSamePubKey.serialize().sha256()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `signNodeInfo associates signature to with node info`() {
|
||||
// given
|
||||
// Create node info.
|
||||
val organisation = "Test"
|
||||
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
||||
requestStorage.approveRequest(requestId, "TestUser")
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisation, locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestId, certPath, emptyList())
|
||||
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfo)
|
||||
// Some random bytes
|
||||
val signature = keyPair.sign(nodeInfo.serialize())
|
||||
|
||||
// when
|
||||
nodeInfoStorage.signNodeInfo(nodeInfoHash, signature)
|
||||
|
||||
// then
|
||||
val signedNodeInfo = nodeInfoStorage.getSignedNodeInfo(nodeInfoHash)
|
||||
assertEquals(signature, signedNodeInfo?.sig)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getUnsignedNodeInfoBytes return node info bytes`() {
|
||||
// given
|
||||
// Create node info.
|
||||
val organisation = "Test"
|
||||
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
||||
requestStorage.approveRequest(requestId, "TestUser")
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val clientCert = X509Utilities.createCertificate(CertificateType.CLIENT_CA, intermediateCACert, intermediateCAKey, CordaX500Name(organisation = organisation, locality = "London", country = "GB"), keyPair.public)
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
requestStorage.putCertificatePath(requestId, certPath, emptyList())
|
||||
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfo)
|
||||
|
||||
// when
|
||||
val nodeInfoBytes = nodeInfoStorage.getUnsignedNodeInfoBytes()
|
||||
|
||||
// then
|
||||
assertTrue(nodeInfoBytes.containsKey(nodeInfoHash))
|
||||
assertEquals(nodeInfo, nodeInfoBytes[nodeInfoHash]?.deserialize()!!)
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package com.r3.corda.networkmanage.common.signer
|
||||
|
||||
import com.nhaarman.mockito_kotlin.*
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.serialization.serialize
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class NetworkMapSignerTest : TestBase() {
|
||||
private lateinit var signer: Signer
|
||||
private lateinit var networkMapStorage: NetworkMapStorage
|
||||
private lateinit var networkMapSigner: NetworkMapSigner
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
signer = mock()
|
||||
networkMapStorage = mock()
|
||||
networkMapSigner = NetworkMapSigner(networkMapStorage, signer)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `signNetworkMap builds and signs network map`() {
|
||||
// given
|
||||
val signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
|
||||
val detachedNodeInfoHashes = listOf(SecureHash.randomSHA256())
|
||||
val networkMapParameters = createNetworkParameters()
|
||||
whenever(networkMapStorage.getCurrentNetworkMapNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes)
|
||||
whenever(networkMapStorage.getDetachedSignedAndValidNodeInfoHashes()).thenReturn(detachedNodeInfoHashes)
|
||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters)
|
||||
whenever(signer.sign(any())).thenReturn(mock())
|
||||
|
||||
// when
|
||||
networkMapSigner.signNetworkMap()
|
||||
|
||||
// then
|
||||
// Verify networkMapStorage calls
|
||||
verify(networkMapStorage).getCurrentNetworkMapNodeInfoHashes(any())
|
||||
verify(networkMapStorage).getDetachedSignedAndValidNodeInfoHashes()
|
||||
verify(networkMapStorage).getLatestNetworkParameters()
|
||||
argumentCaptor<SignedNetworkMap>().apply {
|
||||
verify(networkMapStorage).saveNetworkMap(capture())
|
||||
val networkMap = firstValue.networkMap
|
||||
assertEquals(networkMapParameters.serialize().hash.toString(), networkMap.parametersHash)
|
||||
assertEquals(signedNodeInfoHashes.size + detachedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
|
||||
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes.map { it.toString() }))
|
||||
assertTrue(networkMap.nodeInfoHashes.containsAll(detachedNodeInfoHashes.map { it.toString() }))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `signNetworkMap does NOT create a new network map if there are no changes`() {
|
||||
// given
|
||||
val networkMapParameters = createNetworkParameters()
|
||||
val networkMapParametersHash = networkMapParameters.serialize().bytes.sha256()
|
||||
val networkMap = NetworkMap(emptyList(), networkMapParametersHash.toString())
|
||||
val signedNetworkMap = SignedNetworkMap(networkMap, mock())
|
||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
|
||||
whenever(networkMapStorage.getCurrentNetworkMapNodeInfoHashes(any())).thenReturn(emptyList())
|
||||
whenever(networkMapStorage.getDetachedSignedAndValidNodeInfoHashes()).thenReturn(emptyList())
|
||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters)
|
||||
|
||||
// when
|
||||
networkMapSigner.signNetworkMap()
|
||||
|
||||
// then
|
||||
// Verify networkMapStorage is not called
|
||||
verify(networkMapStorage, never()).saveNetworkMap(any())
|
||||
}
|
||||
}
|
@ -4,29 +4,33 @@ import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import com.nhaarman.mockito_kotlin.times
|
||||
import com.nhaarman.mockito_kotlin.verify
|
||||
import com.r3.corda.networkmanage.common.persistence.*
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateResponse
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificationRequestStorage
|
||||
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import com.r3.corda.networkmanage.doorman.signer.DefaultCsrHandler
|
||||
import com.r3.corda.networkmanage.doorman.signer.Signer
|
||||
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.node.utilities.X509Utilities
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DefaultRequestProcessorTest {
|
||||
class DefaultRequestProcessorTest : TestBase() {
|
||||
@Test
|
||||
fun `get response`() {
|
||||
val keyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
val cert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(locality = "London", organisation = "Test", country = "GB"), keyPair)
|
||||
|
||||
val requestStorage: CertificationRequestStorage = mock {
|
||||
on { getRequest("New") }.thenReturn(CertificateSigningRequest(status = RequestStatus.New))
|
||||
on { getRequest("Signed") }.thenReturn(CertificateSigningRequest(status = RequestStatus.Signed, certificateData = CertificateData("", buildCertPath(cert.toX509Certificate()).encoded, CertificateStatus.VALID)))
|
||||
on { getRequest("Rejected") }.thenReturn(CertificateSigningRequest(status = RequestStatus.Rejected, remark = "Random reason"))
|
||||
on { getRequest("New") }.thenReturn(certificateSigningRequest())
|
||||
on { getRequest("Signed") }.thenReturn(certificateSigningRequest(status = RequestStatus.Signed, certData = certificateData("", CertificateStatus.VALID, buildCertPath(cert.toX509Certificate()))))
|
||||
on { getRequest("Rejected") }.thenReturn(certificateSigningRequest(status = RequestStatus.Rejected, remark = "Random reason"))
|
||||
}
|
||||
val signer: Signer = mock()
|
||||
val signer: LocalSigner = mock()
|
||||
val requestProcessor = DefaultCsrHandler(requestStorage, signer)
|
||||
|
||||
assertEquals(CertificateResponse.NotReady, requestProcessor.getResponse("random"))
|
||||
@ -43,17 +47,17 @@ class DefaultRequestProcessorTest {
|
||||
|
||||
val requestStorage: CertificationRequestStorage = mock {
|
||||
on { getRequests(RequestStatus.Approved) }.thenReturn(listOf(
|
||||
CertificateSigningRequest(requestId = "1", request = request1.encoded),
|
||||
CertificateSigningRequest(requestId = "2", request = request2.encoded),
|
||||
CertificateSigningRequest(requestId = "3", request = request3.encoded)
|
||||
certificateSigningRequest(requestId = "1", request = request1, status = RequestStatus.Approved),
|
||||
certificateSigningRequest(requestId = "2", request = request2, status = RequestStatus.Approved),
|
||||
certificateSigningRequest(requestId = "3", request = request3, status = RequestStatus.Approved)
|
||||
))
|
||||
}
|
||||
val signer: Signer = mock()
|
||||
val signer: LocalSigner = mock()
|
||||
val requestProcessor = DefaultCsrHandler(requestStorage, signer)
|
||||
|
||||
requestProcessor.processApprovedRequests()
|
||||
|
||||
verify(signer, times(3)).sign(any())
|
||||
verify(signer, times(3)).createSignedClientCertificate(any())
|
||||
verify(requestStorage, times(1)).getRequests(any())
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
package com.r3.corda.networkmanage.doorman
|
||||
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.typesafe.config.ConfigException
|
||||
import net.corda.core.utilities.seconds
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class DoormanParametersTest {
|
||||
class DoormanParametersTest : TestBase() {
|
||||
private val testDummyPath = ".${File.separator}testDummyPath.jks"
|
||||
private val validInitialNetworkConfigPath = File(javaClass.getResource("/initial-network-parameters.conf").toURI()).absolutePath
|
||||
private val validConfigPath = File(javaClass.getResource("/doorman.conf").toURI()).absolutePath
|
||||
|
@ -4,7 +4,11 @@ import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import com.nhaarman.mockito_kotlin.times
|
||||
import com.nhaarman.mockito_kotlin.verify
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||
import com.r3.corda.networkmanage.common.signer.NetworkMap
|
||||
import com.r3.corda.networkmanage.common.signer.SignedNetworkMap
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
|
||||
@ -12,19 +16,15 @@ import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.serialization.SerializationDefaults
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.node.serialization.KryoServerSerializationScheme
|
||||
import net.corda.node.utilities.CertificateType
|
||||
import net.corda.node.utilities.X509Utilities
|
||||
import net.corda.nodeapi.internal.serialization.*
|
||||
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
||||
import net.corda.testing.common.internal.testNetworkParameters
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.codehaus.jackson.map.ObjectMapper
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
@ -34,31 +34,12 @@ import javax.ws.rs.core.MediaType
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class NodeInfoWebServiceTest {
|
||||
class NodeInfoWebServiceTest : TestBase() {
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(locality = "London", organisation = "R3 LTD", country = "GB", commonName = "Corda Node Root CA"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
|
||||
|
||||
companion object {
|
||||
@BeforeClass
|
||||
@JvmStatic
|
||||
fun initSerialization() {
|
||||
try {
|
||||
SerializationDefaults.SERIALIZATION_FACTORY = SerializationFactoryImpl().apply {
|
||||
registerScheme(KryoServerSerializationScheme())
|
||||
registerScheme(AMQPServerSerializationScheme())
|
||||
}
|
||||
SerializationDefaults.P2P_CONTEXT = KRYO_P2P_CONTEXT
|
||||
SerializationDefaults.RPC_SERVER_CONTEXT = KRYO_RPC_SERVER_CONTEXT
|
||||
SerializationDefaults.STORAGE_CONTEXT = KRYO_STORAGE_CONTEXT
|
||||
SerializationDefaults.CHECKPOINT_CONTEXT = KRYO_CHECKPOINT_CONTEXT
|
||||
} catch (ignored: Exception) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `submit nodeInfo`() {
|
||||
// Create node info.
|
||||
@ -74,8 +55,7 @@ class NodeInfoWebServiceTest {
|
||||
on { getCertificatePath(any()) }.thenReturn(certPath)
|
||||
}
|
||||
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0),
|
||||
NodeInfoWebService(nodeInfoStorage, testNetworkParameters(emptyList()))).use {
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock())).use {
|
||||
it.start()
|
||||
val registerURL = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/register")
|
||||
val nodeInfoAndSignature = SignedData(nodeInfo.serialize(), digitalSignature).serialize().bytes
|
||||
@ -101,8 +81,7 @@ class NodeInfoWebServiceTest {
|
||||
on { getCertificatePath(any()) }.thenReturn(certPath)
|
||||
}
|
||||
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0),
|
||||
NodeInfoWebService(nodeInfoStorage, testNetworkParameters(emptyList()))).use {
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock())).use {
|
||||
it.start()
|
||||
val registerURL = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/register")
|
||||
val nodeInfoAndSignature = SignedData(nodeInfo.serialize(), digitalSignature).serialize().bytes
|
||||
@ -116,18 +95,16 @@ class NodeInfoWebServiceTest {
|
||||
|
||||
@Test
|
||||
fun `get network map`() {
|
||||
val networkMapList = listOf(SecureHash.randomSHA256().toString(), SecureHash.randomSHA256().toString())
|
||||
val nodeInfoStorage: NodeInfoStorage = mock {
|
||||
on { getNodeInfoHashes() }.thenReturn(networkMapList)
|
||||
val hashedNetworkMap = NetworkMap(listOf(SecureHash.randomSHA256().toString(), SecureHash.randomSHA256().toString()), SecureHash.randomSHA256().toString())
|
||||
val networkMapStorage: NetworkMapStorage = mock {
|
||||
on { getCurrentNetworkMap() }.thenReturn(SignedNetworkMap(hashedNetworkMap, mock()))
|
||||
}
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0),
|
||||
NodeInfoWebService(nodeInfoStorage, testNetworkParameters(emptyList()))).use {
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage)).use {
|
||||
it.start()
|
||||
val conn = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}").openConnection() as HttpURLConnection
|
||||
val response = conn.inputStream.bufferedReader().use { it.readLine() }
|
||||
val list = ObjectMapper().readValue(response, List::class.java)
|
||||
verify(nodeInfoStorage, times(1)).getNodeInfoHashes()
|
||||
assertEquals(networkMapList, list)
|
||||
val signedHashedNetworkMap = conn.inputStream.readBytes().deserialize<SignedNetworkMap>()
|
||||
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
||||
assertEquals(signedHashedNetworkMap.networkMap, hashedNetworkMap)
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,20 +115,20 @@ class NodeInfoWebServiceTest {
|
||||
val certPath = buildCertPath(clientCert.toX509Certificate(), intermediateCACert.toX509Certificate(), rootCACert.toX509Certificate())
|
||||
val nodeInfo = NodeInfo(listOf(NetworkHostAndPort("my.company.com", 1234)), listOf(PartyAndCertificate(certPath)), 1, serial = 1L)
|
||||
|
||||
val nodeInfoHash = nodeInfo.serialize().sha256().toString()
|
||||
val nodeInfoHash = nodeInfo.serialize().sha256()
|
||||
|
||||
val nodeInfoStorage: NodeInfoStorage = mock {
|
||||
on { getNodeInfo(nodeInfoHash) }.thenReturn(nodeInfo)
|
||||
val serializedNodeInfo = nodeInfo.serialize()
|
||||
on { getSignedNodeInfo(nodeInfoHash) }.thenReturn(SignedData(serializedNodeInfo, keyPair.sign(serializedNodeInfo)))
|
||||
}
|
||||
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0),
|
||||
NodeInfoWebService(nodeInfoStorage, testNetworkParameters(emptyList()))).use {
|
||||
DoormanServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock())).use {
|
||||
it.start()
|
||||
val nodeInfoURL = URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/$nodeInfoHash")
|
||||
val conn = nodeInfoURL.openConnection()
|
||||
val nodeInfoResponse = conn.inputStream.readBytes().deserialize<NodeInfo>()
|
||||
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
|
||||
assertEquals(nodeInfo, nodeInfoResponse)
|
||||
val nodeInfoResponse = conn.inputStream.readBytes().deserialize<SignedData<NodeInfo>>()
|
||||
verify(nodeInfoStorage, times(1)).getSignedNodeInfo(nodeInfoHash)
|
||||
assertEquals(nodeInfo, nodeInfoResponse.verified())
|
||||
|
||||
assertFailsWith(FileNotFoundException::class) {
|
||||
URL("http://${it.hostAndPort}/api/${NodeInfoWebService.networkMapPath}/${SecureHash.randomSHA256()}").openConnection().getInputStream()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.r3.corda.networkmanage.doorman
|
||||
|
||||
import com.nhaarman.mockito_kotlin.*
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.common.persistence.CertificateResponse
|
||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||
@ -36,7 +37,7 @@ import java.util.zip.ZipInputStream
|
||||
import javax.ws.rs.core.MediaType
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class RegistrationWebServiceTest {
|
||||
class RegistrationWebServiceTest : TestBase() {
|
||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
private val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(commonName = "Corda Node Root CA", locality = "London", organisation = "R3 Ltd", country = "GB"), rootCAKey)
|
||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||
@ -141,9 +142,7 @@ class RegistrationWebServiceTest {
|
||||
}
|
||||
|
||||
startSigningServer(storage)
|
||||
|
||||
assertThat(pollForResponse(id)).isEqualTo(PollResponse.NotReady)
|
||||
|
||||
storage.processApprovedRequests()
|
||||
|
||||
val certificates = (pollForResponse(id) as PollResponse.Ready).certChain
|
||||
|
@ -1,15 +1,15 @@
|
||||
package com.r3.corda.networkmanage.hsm.authentication
|
||||
|
||||
import CryptoServerCXI.CryptoServerCXI
|
||||
import CryptoServerJCE.CryptoServerProvider
|
||||
import com.nhaarman.mockito_kotlin.*
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.Console
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class AuthenticatorTest {
|
||||
class AuthenticatorTest : TestBase() {
|
||||
|
||||
private lateinit var provider: CryptoServerProvider
|
||||
private lateinit var console: Console
|
||||
@ -17,7 +17,7 @@ class AuthenticatorTest {
|
||||
@Before
|
||||
fun setUp() {
|
||||
provider = mock()
|
||||
whenever(provider.cryptoServer).thenReturn(mock<CryptoServerCXI>())
|
||||
whenever(provider.cryptoServer).thenReturn(mock())
|
||||
console = mock()
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.r3.corda.networkmanage.hsm.configuration
|
||||
|
||||
import com.r3.corda.networkmanage.TestBase
|
||||
import com.r3.corda.networkmanage.hsm.authentication.AuthMode
|
||||
import com.typesafe.config.ConfigException
|
||||
import org.junit.Test
|
||||
@ -7,7 +8,7 @@ import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class ConfigurationTest {
|
||||
class ConfigurationTest : TestBase() {
|
||||
private val validConfigPath = File(javaClass.getResource("/hsm.conf").toURI()).absolutePath
|
||||
private val invalidConfigPath = File(javaClass.getResource("/hsm_fail.conf").toURI()).absolutePath
|
||||
|
||||
|
Reference in New Issue
Block a user