mirror of
https://github.com/corda/corda.git
synced 2025-01-28 23:24:29 +00:00
ENT-1226 Check minimum platform version when submitting node info (#300)
* Adding min platform version check when submitting node info * Return error message to developer * Fixing integration test * Added todo to move checks out of data layer * Added extra logging in nodeinfowebservice and use nodeinfo.verified instead of deserialize * Tidy up tests * Cache network parameters * Add NodeInfoWithSigned class to stop calling to only verify node data once * Fixing review comments * Return correct response code if doorman not initialised properly * Fix merge conflict
This commit is contained in:
parent
2832eb489b
commit
a65db712c7
@ -1,7 +1,6 @@
|
|||||||
package com.r3.corda.networkmanage.common.persistence
|
package com.r3.corda.networkmanage.common.persistence
|
||||||
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SignedData
|
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
@ -27,5 +26,5 @@ interface NodeInfoStorage {
|
|||||||
* @param signedNodeInfo signed node info data to be stored
|
* @param signedNodeInfo signed node info data to be stored
|
||||||
* @return hash for the newly created node info entry
|
* @return hash for the newly created node info entry
|
||||||
*/
|
*/
|
||||||
fun putNodeInfo(signedNodeInfo: SignedNodeInfo): SecureHash
|
fun putNodeInfo(signedNodeInfo: NodeInfoWithSigned): SecureHash
|
||||||
}
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.r3.corda.networkmanage.common.persistence
|
||||||
|
|
||||||
|
import net.corda.core.node.NodeInfo
|
||||||
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
|
|
||||||
|
class NodeInfoWithSigned(val signedNodeInfo: SignedNodeInfo) {
|
||||||
|
val nodeInfo: NodeInfo = signedNodeInfo.verified()
|
||||||
|
}
|
@ -17,10 +17,12 @@ import java.security.cert.CertPath
|
|||||||
* Database implementation of the [NetworkMapStorage] interface
|
* Database implementation of the [NetworkMapStorage] interface
|
||||||
*/
|
*/
|
||||||
class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeInfoStorage {
|
class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeInfoStorage {
|
||||||
override fun putNodeInfo(signedNodeInfo: SignedNodeInfo): SecureHash {
|
override fun putNodeInfo(nodeInfoWithSigned: NodeInfoWithSigned): SecureHash {
|
||||||
val nodeInfo = signedNodeInfo.verified()
|
val nodeInfo = nodeInfoWithSigned.nodeInfo
|
||||||
|
val signedNodeInfo = nodeInfoWithSigned.signedNodeInfo
|
||||||
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts[0].certPath.certificates.find { CertRole.extract(it) == CertRole.NODE_CA }
|
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts[0].certPath.certificates.find { CertRole.extract(it) == CertRole.NODE_CA }
|
||||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||||
|
// TODO Move these checks out of data access layer
|
||||||
val request = nodeCaCert?.let {
|
val request = nodeCaCert?.let {
|
||||||
singleRequestWhere(CertificateDataEntity::class.java) { builder, path ->
|
singleRequestWhere(CertificateDataEntity::class.java) { builder, path ->
|
||||||
val certPublicKeyHashEq = builder.equal(path.get<String>(CertificateDataEntity::publicKeyHash.name), it.publicKey.encoded.sha256().toString())
|
val certPublicKeyHashEq = builder.equal(path.get<String>(CertificateDataEntity::publicKeyHash.name), it.publicKey.encoded.sha256().toString())
|
||||||
|
@ -5,12 +5,16 @@ import com.google.common.cache.CacheLoader
|
|||||||
import com.google.common.cache.LoadingCache
|
import com.google.common.cache.LoadingCache
|
||||||
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
|
||||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||||
|
import com.r3.corda.networkmanage.common.persistence.NodeInfoWithSigned
|
||||||
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
|
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
|
||||||
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService.Companion.NETWORK_MAP_PATH
|
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService.Companion.NETWORK_MAP_PATH
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.InvalidKeyException
|
import java.security.InvalidKeyException
|
||||||
@ -29,35 +33,41 @@ import javax.ws.rs.core.Response.status
|
|||||||
class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
||||||
private val networkMapStorage: NetworkMapStorage,
|
private val networkMapStorage: NetworkMapStorage,
|
||||||
private val config: NetworkMapConfig) {
|
private val config: NetworkMapConfig) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
val log = contextLogger()
|
||||||
const val NETWORK_MAP_PATH = "network-map"
|
const val NETWORK_MAP_PATH = "network-map"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val networkMapCache: LoadingCache<Boolean, SignedNetworkMap?> = CacheBuilder.newBuilder()
|
private val networkMapCache: LoadingCache<Boolean, Pair<SignedNetworkMap?, NetworkParameters?>> = CacheBuilder.newBuilder()
|
||||||
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
||||||
.build(CacheLoader.from { _ -> networkMapStorage.getCurrentNetworkMap() })
|
.build(CacheLoader.from { _ -> Pair(networkMapStorage.getCurrentNetworkMap(), networkMapStorage.getCurrentNetworkParameters()) })
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("publish")
|
@Path("publish")
|
||||||
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
fun registerNode(input: InputStream): Response {
|
fun registerNode(input: InputStream): Response {
|
||||||
val registrationData = input.readBytes().deserialize<SignedNodeInfo>()
|
val signedNodeInfo = input.readBytes().deserialize<SignedNodeInfo>()
|
||||||
return try {
|
return try {
|
||||||
// Store the NodeInfo
|
// Store the NodeInfo
|
||||||
nodeInfoStorage.putNodeInfo(registrationData)
|
val nodeInfoWithSignature = NodeInfoWithSigned(signedNodeInfo)
|
||||||
|
verifyNodeInfo(nodeInfoWithSignature.nodeInfo)
|
||||||
|
nodeInfoStorage.putNodeInfo(nodeInfoWithSignature)
|
||||||
ok()
|
ok()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Catch exceptions thrown by signature verification.
|
// Catch exceptions thrown by signature verification.
|
||||||
when (e) {
|
when (e) {
|
||||||
|
is NetworkMapNotInitialisedException -> status(Response.Status.SERVICE_UNAVAILABLE).entity(e.message)
|
||||||
|
is InvalidPlatformVersionException -> status(Response.Status.BAD_REQUEST).entity(e.message)
|
||||||
is IllegalArgumentException, is InvalidKeyException, is SignatureException -> status(Response.Status.UNAUTHORIZED).entity(e.message)
|
is IllegalArgumentException, is InvalidKeyException, is SignatureException -> status(Response.Status.UNAUTHORIZED).entity(e.message)
|
||||||
// Rethrow e if its not one of the expected exception, the server will return http 500 internal error.
|
// Rethrow e if its not one of the expected exception, the server will return http 500 internal error.
|
||||||
else -> throw e
|
else -> throw e
|
||||||
}
|
}
|
||||||
}.build()
|
}.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
fun getNetworkMap(): Response = createResponse(networkMapCache.get(true), addCacheTimeout = true)
|
fun getNetworkMap(): Response = createResponse(networkMapCache.get(true).first, addCacheTimeout = true)
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("node-info/{nodeInfoHash}")
|
@Path("node-info/{nodeInfoHash}")
|
||||||
@ -80,6 +90,18 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
return ok(request.getHeader("X-Forwarded-For")?.split(",")?.first() ?: "${request.remoteHost}:${request.remotePort}").build()
|
return ok(request.getHeader("X-Forwarded-For")?.split(",")?.first() ?: "${request.remoteHost}:${request.remotePort}").build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun verifyNodeInfo(nodeInfo: NodeInfo) {
|
||||||
|
val minimumPlatformVersion = networkMapCache.get(true).second?.minimumPlatformVersion
|
||||||
|
if (minimumPlatformVersion == null) {
|
||||||
|
log.error("Network parameters have not been initialised")
|
||||||
|
throw NetworkMapNotInitialisedException("Network parameters have not been initialised")
|
||||||
|
}
|
||||||
|
if (nodeInfo.platformVersion < minimumPlatformVersion) {
|
||||||
|
log.error("Minimum platform version is $minimumPlatformVersion")
|
||||||
|
throw InvalidPlatformVersionException("Minimum platform version is $minimumPlatformVersion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createResponse(payload: Any?, addCacheTimeout: Boolean = false): Response {
|
private fun createResponse(payload: Any?, addCacheTimeout: Boolean = false): Response {
|
||||||
return if (payload != null) {
|
return if (payload != null) {
|
||||||
val ok = Response.ok(payload.serialize().bytes)
|
val ok = Response.ok(payload.serialize().bytes)
|
||||||
@ -91,4 +113,7 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
status(Response.Status.NOT_FOUND)
|
status(Response.Status.NOT_FOUND)
|
||||||
}.build()
|
}.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NetworkMapNotInitialisedException(message: String?) : Exception(message)
|
||||||
|
class InvalidPlatformVersionException(message: String?) : Exception(message)
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
assertThat(validNodeInfoHash).containsOnly(nodeInfoHashA, nodeInfoHashB)
|
assertThat(validNodeInfoHash).containsOnly(nodeInfoHashA, nodeInfoHashB)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createValidSignedNodeInfo(organisation: String): SignedNodeInfo {
|
private fun createValidSignedNodeInfo(organisation: String): NodeInfoWithSigned {
|
||||||
val nodeInfoBuilder = TestNodeInfoBuilder()
|
val nodeInfoBuilder = TestNodeInfoBuilder()
|
||||||
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
||||||
requestStorage.markRequestTicketCreated(requestId)
|
requestStorage.markRequestTicketCreated(requestId)
|
||||||
@ -156,6 +156,6 @@ class PersistentNetworkMapStorageTest : TestBase() {
|
|||||||
val (identity) = nodeInfoBuilder.addIdentity(CordaX500Name(organisation, "London", "GB"))
|
val (identity) = nodeInfoBuilder.addIdentity(CordaX500Name(organisation, "London", "GB"))
|
||||||
val nodeCaCertPath = X509CertificateFactory().generateCertPath(identity.certPath.certificates.drop(1))
|
val nodeCaCertPath = X509CertificateFactory().generateCertPath(identity.certPath.certificates.drop(1))
|
||||||
requestStorage.putCertificatePath(requestId, nodeCaCertPath, emptyList())
|
requestStorage.putCertificatePath(requestId, nodeCaCertPath, emptyList())
|
||||||
return nodeInfoBuilder.buildWithSigned().second
|
return NodeInfoWithSigned(nodeInfoBuilder.buildWithSigned().second)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,7 +28,7 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
class PersitenceNodeInfoStorageTest : TestBase() {
|
class PersistentNodeInfoStorageTest : TestBase() {
|
||||||
private lateinit var requestStorage: CertificationRequestStorage
|
private lateinit var requestStorage: CertificationRequestStorage
|
||||||
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
|
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
|
||||||
private lateinit var persistence: CordaPersistence
|
private lateinit var persistence: CordaPersistence
|
||||||
@ -85,34 +85,34 @@ class PersitenceNodeInfoStorageTest : TestBase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `getNodeInfo returns persisted SignedNodeInfo using the hash of just the NodeInfo`() {
|
fun `getNodeInfo returns persisted SignedNodeInfo using the hash of just the NodeInfo`() {
|
||||||
// given
|
// given
|
||||||
val (nodeInfoA, signedNodeInfoA) = createValidSignedNodeInfo("TestA")
|
val (nodeA) = createValidSignedNodeInfo("TestA")
|
||||||
val (nodeInfoB, signedNodeInfoB) = createValidSignedNodeInfo("TestB")
|
val (nodeB) = createValidSignedNodeInfo("TestB")
|
||||||
|
|
||||||
// Put signed node info data
|
// Put signed node info data
|
||||||
nodeInfoStorage.putNodeInfo(signedNodeInfoA)
|
nodeInfoStorage.putNodeInfo(nodeA)
|
||||||
nodeInfoStorage.putNodeInfo(signedNodeInfoB)
|
nodeInfoStorage.putNodeInfo(nodeB)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val persistedSignedNodeInfoA = nodeInfoStorage.getNodeInfo(nodeInfoA.serialize().hash)
|
val persistedSignedNodeInfoA = nodeInfoStorage.getNodeInfo(nodeA.nodeInfo.serialize().hash)
|
||||||
val persistedSignedNodeInfoB = nodeInfoStorage.getNodeInfo(nodeInfoB.serialize().hash)
|
val persistedSignedNodeInfoB = nodeInfoStorage.getNodeInfo(nodeB.nodeInfo.serialize().hash)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(persistedSignedNodeInfoA?.verified(), nodeInfoA)
|
assertEquals(persistedSignedNodeInfoA?.verified(), nodeA.nodeInfo)
|
||||||
assertEquals(persistedSignedNodeInfoB?.verified(), nodeInfoB)
|
assertEquals(persistedSignedNodeInfoB?.verified(), nodeB.nodeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `same public key with different node info`() {
|
fun `same public key with different node info`() {
|
||||||
// Create node info.
|
// Create node info.
|
||||||
val (nodeInfo1, signedNodeInfo1, key) = createValidSignedNodeInfo("Test", serial = 1)
|
val (node1, key) = createValidSignedNodeInfo("Test", serial = 1)
|
||||||
val nodeInfo2 = nodeInfo1.copy(serial = 2)
|
val nodeInfo2 = node1.nodeInfo.copy(serial = 2)
|
||||||
val signedNodeInfo2 = nodeInfo2.signWith(listOf(key))
|
val node2 = NodeInfoWithSigned(nodeInfo2.signWith(listOf(key)))
|
||||||
|
|
||||||
val nodeInfo1Hash = nodeInfoStorage.putNodeInfo(signedNodeInfo1)
|
val nodeInfo1Hash = nodeInfoStorage.putNodeInfo(node1)
|
||||||
assertEquals(nodeInfo1, nodeInfoStorage.getNodeInfo(nodeInfo1Hash)?.verified())
|
assertEquals(node1.nodeInfo, nodeInfoStorage.getNodeInfo(nodeInfo1Hash)?.verified())
|
||||||
|
|
||||||
// This should replace the node info.
|
// This should replace the node info.
|
||||||
nodeInfoStorage.putNodeInfo(signedNodeInfo2)
|
nodeInfoStorage.putNodeInfo(node2)
|
||||||
|
|
||||||
// Old node info should be removed.
|
// Old node info should be removed.
|
||||||
assertNull(nodeInfoStorage.getNodeInfo(nodeInfo1Hash))
|
assertNull(nodeInfoStorage.getNodeInfo(nodeInfo1Hash))
|
||||||
@ -122,17 +122,17 @@ class PersitenceNodeInfoStorageTest : TestBase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `putNodeInfo persists SignedNodeInfo with its signature`() {
|
fun `putNodeInfo persists SignedNodeInfo with its signature`() {
|
||||||
// given
|
// given
|
||||||
val (_, signedNodeInfo) = createValidSignedNodeInfo("Test")
|
val (nodeInfoWithSigned) = createValidSignedNodeInfo("Test")
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val nodeInfoHash = nodeInfoStorage.putNodeInfo(signedNodeInfo)
|
val nodeInfoHash = nodeInfoStorage.putNodeInfo(nodeInfoWithSigned)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val persistedSignedNodeInfo = nodeInfoStorage.getNodeInfo(nodeInfoHash)
|
val persistedSignedNodeInfo = nodeInfoStorage.getNodeInfo(nodeInfoHash)
|
||||||
assertThat(persistedSignedNodeInfo?.signatures).isEqualTo(signedNodeInfo.signatures)
|
assertThat(persistedSignedNodeInfo?.signatures).isEqualTo(nodeInfoWithSigned.signedNodeInfo.signatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createValidSignedNodeInfo(organisation: String, serial: Long = 1): Triple<NodeInfo, SignedNodeInfo, PrivateKey> {
|
private fun createValidSignedNodeInfo(organisation: String, serial: Long = 1): Pair<NodeInfoWithSigned, PrivateKey> {
|
||||||
val nodeInfoBuilder = TestNodeInfoBuilder()
|
val nodeInfoBuilder = TestNodeInfoBuilder()
|
||||||
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
val requestId = requestStorage.saveRequest(createRequest(organisation).first)
|
||||||
requestStorage.markRequestTicketCreated(requestId)
|
requestStorage.markRequestTicketCreated(requestId)
|
||||||
@ -140,7 +140,7 @@ class PersitenceNodeInfoStorageTest : TestBase() {
|
|||||||
val (identity, key) = nodeInfoBuilder.addIdentity(CordaX500Name(organisation, "London", "GB"))
|
val (identity, key) = nodeInfoBuilder.addIdentity(CordaX500Name(organisation, "London", "GB"))
|
||||||
val nodeCaCertPath = X509CertificateFactory().generateCertPath(identity.certPath.certificates.drop(1))
|
val nodeCaCertPath = X509CertificateFactory().generateCertPath(identity.certPath.certificates.drop(1))
|
||||||
requestStorage.putCertificatePath(requestId, nodeCaCertPath, emptyList())
|
requestStorage.putCertificatePath(requestId, nodeCaCertPath, emptyList())
|
||||||
val (nodeInfo, signedNodeInfo) = nodeInfoBuilder.buildWithSigned(serial)
|
val (_, signedNodeInfo) = nodeInfoBuilder.buildWithSigned(serial)
|
||||||
return Triple(nodeInfo, signedNodeInfo, key)
|
return Pair(NodeInfoWithSigned(signedNodeInfo), key)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,13 +25,15 @@ import net.corda.testing.SerializationEnvironmentRule
|
|||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||||
import net.corda.testing.internal.createNodeInfoAndSigned
|
import net.corda.testing.internal.createNodeInfoAndSigned
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.apache.commons.io.IOUtils
|
||||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
import org.assertj.core.api.Assertions.*
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.IOException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
import java.nio.charset.Charset
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import javax.ws.rs.core.MediaType
|
import javax.ws.rs.core.MediaType
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -44,7 +46,7 @@ class NodeInfoWebServiceTest {
|
|||||||
private lateinit var rootCaCert: X509Certificate
|
private lateinit var rootCaCert: X509Certificate
|
||||||
private lateinit var intermediateCa: CertificateAndKeyPair
|
private lateinit var intermediateCa: CertificateAndKeyPair
|
||||||
|
|
||||||
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun init() {
|
fun init() {
|
||||||
@ -55,10 +57,13 @@ class NodeInfoWebServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `submit nodeInfo`() {
|
fun `submit nodeInfo`() {
|
||||||
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
|
on { getCurrentNetworkParameters() }.thenReturn(testNetworkParameters(emptyList()))
|
||||||
|
}
|
||||||
// Create node info.
|
// Create node info.
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
||||||
|
|
||||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), mock(), testNetworkMapConfig)).use {
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
||||||
it.start()
|
it.start()
|
||||||
val nodeInfoAndSignature = signedNodeInfo.serialize().bytes
|
val nodeInfoAndSignature = signedNodeInfo.serialize().bytes
|
||||||
// Post node info and signature to doorman, this should pass without any exception.
|
// Post node info and signature to doorman, this should pass without any exception.
|
||||||
@ -66,6 +71,38 @@ class NodeInfoWebServiceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `submit old nodeInfo`() {
|
||||||
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
|
on { getCurrentNetworkParameters() }.thenReturn(testNetworkParameters(emptyList(), minimumPlatformVersion = 2))
|
||||||
|
}
|
||||||
|
// Create node info.
|
||||||
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
|
|
||||||
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
||||||
|
it.start()
|
||||||
|
val nodeInfoAndSignature = signedNodeInfo.serialize().bytes
|
||||||
|
assertThatThrownBy { it.doPost("publish", nodeInfoAndSignature) }
|
||||||
|
.hasMessageStartingWith("Response Code 400: Minimum platform version is 2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `submit nodeInfo when no network parameters`() {
|
||||||
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
|
on { getCurrentNetworkParameters() }.thenReturn(null)
|
||||||
|
}
|
||||||
|
// Create node info.
|
||||||
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
|
|
||||||
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
||||||
|
it.start()
|
||||||
|
val nodeInfoAndSignature = signedNodeInfo.serialize().bytes
|
||||||
|
assertThatThrownBy { it.doPost("publish", nodeInfoAndSignature) }
|
||||||
|
.hasMessageStartingWith("Response Code 503: Network parameters have not been initialised")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get network map`() {
|
fun `get network map`() {
|
||||||
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256())
|
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256())
|
||||||
@ -136,7 +173,10 @@ class NodeInfoWebServiceTest {
|
|||||||
requestMethod = "POST"
|
requestMethod = "POST"
|
||||||
setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
|
setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
|
||||||
outputStream.write(payload)
|
outputStream.write(payload)
|
||||||
inputStream.close() // This will give us a nice IOException if the response isn't HTTP 200
|
if (responseCode != 200) {
|
||||||
|
throw IOException("Response Code $responseCode: ${IOUtils.toString(errorStream, Charset.defaultCharset())}")
|
||||||
|
}
|
||||||
|
inputStream.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,17 +22,17 @@ class TestNodeInfoBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build(serial: Long = 1): NodeInfo {
|
fun build(serial: Long = 1, platformVersion: Int = 1): NodeInfo {
|
||||||
return NodeInfo(
|
return NodeInfo(
|
||||||
listOf(NetworkHostAndPort("my.${identitiesAndPrivateKeys[0].first.party.name.organisation}.com", 1234)),
|
listOf(NetworkHostAndPort("my.${identitiesAndPrivateKeys[0].first.party.name.organisation}.com", 1234)),
|
||||||
identitiesAndPrivateKeys.map { it.first },
|
identitiesAndPrivateKeys.map { it.first },
|
||||||
1,
|
platformVersion,
|
||||||
serial
|
serial
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildWithSigned(serial: Long = 1): Pair<NodeInfo, SignedNodeInfo> {
|
fun buildWithSigned(serial: Long = 1, platformVersion: Int = 1): Pair<NodeInfo, SignedNodeInfo> {
|
||||||
val nodeInfo = build(serial)
|
val nodeInfo = build(serial, platformVersion)
|
||||||
val privateKeys = identitiesAndPrivateKeys.map { it.second }
|
val privateKeys = identitiesAndPrivateKeys.map { it.second }
|
||||||
return Pair(nodeInfo, nodeInfo.signWith(privateKeys))
|
return Pair(nodeInfo, nodeInfo.signWith(privateKeys))
|
||||||
}
|
}
|
||||||
@ -42,10 +42,10 @@ class TestNodeInfoBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createNodeInfoAndSigned(vararg names: CordaX500Name, serial: Long = 1): Pair<NodeInfo, SignedNodeInfo> {
|
fun createNodeInfoAndSigned(vararg names: CordaX500Name, serial: Long = 1, platformVersion: Int = 1): Pair<NodeInfo, SignedNodeInfo> {
|
||||||
val nodeInfoBuilder = TestNodeInfoBuilder()
|
val nodeInfoBuilder = TestNodeInfoBuilder()
|
||||||
names.forEach { nodeInfoBuilder.addIdentity(it) }
|
names.forEach { nodeInfoBuilder.addIdentity(it) }
|
||||||
return nodeInfoBuilder.buildWithSigned(serial)
|
return nodeInfoBuilder.buildWithSigned(serial, platformVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun NodeInfo.signWith(keys: List<PrivateKey>): SignedNodeInfo {
|
fun NodeInfo.signWith(keys: List<PrivateKey>): SignedNodeInfo {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user