mirror of
https://github.com/corda/corda.git
synced 2024-12-30 17:57:02 +00:00
Added network-parameter REST endpoint for vending signed network parameters. (#252)
For now this only works with the local signer.
This commit is contained in:
parent
c545a58c1d
commit
19df02541a
@ -1,6 +1,7 @@
|
|||||||
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.nodeapi.internal.network.NetworkParameters
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
|
|
||||||
@ -30,10 +31,10 @@ interface NetworkMapStorage {
|
|||||||
fun saveNetworkMap(signedNetworkMap: SignedNetworkMap)
|
fun saveNetworkMap(signedNetworkMap: SignedNetworkMap)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve network parameters by their hash.
|
* Return the signed network parameters object which matches the given hash. The hash is that of the underlying
|
||||||
* @return network parameters corresponding to the given hash or null if it does not exist
|
* [NetworkParameters] object and not the `SignedData<NetworkParameters>` object that's returned.
|
||||||
*/
|
*/
|
||||||
fun getNetworkParameters(parameterHash: SecureHash): NetworkParameters?
|
fun getSignedNetworkParameters(hash: SecureHash): SignedData<NetworkParameters>?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve network map parameters.
|
* Retrieve network map parameters.
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package com.r3.corda.networkmanage.common.persistence
|
package com.r3.corda.networkmanage.common.persistence
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.entity.*
|
import com.r3.corda.networkmanage.common.persistence.entity.*
|
||||||
|
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||||
|
import net.corda.core.crypto.DigitalSignature
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.SignedData
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
@ -14,19 +17,22 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
|
|||||||
/**
|
/**
|
||||||
* Database implementation of the [NetworkMapStorage] interface
|
* Database implementation of the [NetworkMapStorage] interface
|
||||||
*/
|
*/
|
||||||
class PersistentNetworkMapStorage(private val database: CordaPersistence) : NetworkMapStorage {
|
class PersistentNetworkMapStorage(private val database: CordaPersistence, private val localSigner: LocalSigner?) : NetworkMapStorage {
|
||||||
override fun getCurrentNetworkMap(): SignedNetworkMap? = database.transaction {
|
override fun getCurrentNetworkMap(): SignedNetworkMap? {
|
||||||
val networkMapEntity = getCurrentNetworkMapEntity()
|
return database.transaction {
|
||||||
networkMapEntity?.let {
|
getCurrentNetworkMapEntity()?.let {
|
||||||
val signatureAndCertPath = it.signatureAndCertificate()
|
val signatureAndCertPath = it.signatureAndCertificate()
|
||||||
SignedNetworkMap(SerializedBytes(it.networkMap), signatureAndCertPath)
|
SignedNetworkMap(SerializedBytes(it.networkMap), signatureAndCertPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCurrentNetworkParameters(): NetworkParameters? = database.transaction {
|
override fun getCurrentNetworkParameters(): NetworkParameters? {
|
||||||
getCurrentNetworkMapEntity()?.let {
|
return database.transaction {
|
||||||
val parameterHash = it.networkMap.deserialize<NetworkMap>().networkParameterHash
|
getCurrentNetworkMapEntity()?.let {
|
||||||
getNetworkParameters(parameterHash)
|
val netParamsHash = it.networkMap.deserialize<NetworkMap>().networkParameterHash
|
||||||
|
getNetworkParametersEntity(netParamsHash.toString())?.networkParameters()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,61 +47,75 @@ class PersistentNetworkMapStorage(private val database: CordaPersistence) : Netw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNetworkParameters(parameterHash: SecureHash): NetworkParameters? {
|
// TODO The signing cannot occur here as it won't work with an HSM. The signed network parameters needs to be persisted
|
||||||
return getNetworkParametersEntity(parameterHash.toString())?.networkParameters()
|
// into the database.
|
||||||
|
override fun getSignedNetworkParameters(hash: SecureHash): SignedData<NetworkParameters>? {
|
||||||
|
val netParamsBytes = getNetworkParametersEntity(hash.toString())?.parametersBytes ?: return null
|
||||||
|
val sigWithCert = localSigner!!.sign(netParamsBytes)
|
||||||
|
return SignedData(SerializedBytes(netParamsBytes), DigitalSignature.WithKey(sigWithCert.by.publicKey, sigWithCert.signatureBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNodeInfoHashes(certificateStatus: CertificateStatus): List<SecureHash> = database.transaction {
|
override fun getNodeInfoHashes(certificateStatus: CertificateStatus): List<SecureHash> {
|
||||||
val builder = session.criteriaBuilder
|
return database.transaction {
|
||||||
val query = builder.createQuery(String::class.java).run {
|
val builder = session.criteriaBuilder
|
||||||
from(NodeInfoEntity::class.java).run {
|
val query = builder.createQuery(String::class.java).run {
|
||||||
select(get<String>(NodeInfoEntity::nodeInfoHash.name))
|
from(NodeInfoEntity::class.java).run {
|
||||||
.where(builder.equal(get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
select(get<String>(NodeInfoEntity::nodeInfoHash.name))
|
||||||
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
|
.where(builder.equal(get<CertificateSigningRequestEntity>(NodeInfoEntity::certificateSigningRequest.name)
|
||||||
.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name), certificateStatus))
|
.get<CertificateDataEntity>(CertificateSigningRequestEntity::certificateData.name)
|
||||||
|
.get<CertificateStatus>(CertificateDataEntity::certificateStatus.name), certificateStatus))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
session.createQuery(query).resultList.map { SecureHash.parse(it) }
|
||||||
}
|
}
|
||||||
session.createQuery(query).resultList.map { SecureHash.parse(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash = database.transaction {
|
override fun saveNetworkParameters(networkParameters: NetworkParameters): SecureHash {
|
||||||
val bytes = networkParameters.serialize().bytes
|
return database.transaction {
|
||||||
val hash = bytes.sha256()
|
val bytes = networkParameters.serialize().bytes
|
||||||
session.save(NetworkParametersEntity(
|
val hash = bytes.sha256()
|
||||||
parametersBytes = bytes,
|
session.save(NetworkParametersEntity(
|
||||||
parametersHash = hash.toString()
|
parametersBytes = bytes,
|
||||||
))
|
parametersHash = hash.toString()
|
||||||
hash
|
))
|
||||||
|
hash
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getLatestNetworkParameters(): NetworkParameters = getLatestNetworkParametersEntity().networkParameters()
|
override fun getLatestNetworkParameters(): NetworkParameters = getLatestNetworkParametersEntity().networkParameters()
|
||||||
|
|
||||||
private fun getLatestNetworkParametersEntity(): NetworkParametersEntity = database.transaction {
|
private fun getLatestNetworkParametersEntity(): NetworkParametersEntity {
|
||||||
val builder = session.criteriaBuilder
|
return database.transaction {
|
||||||
val query = builder.createQuery(NetworkParametersEntity::class.java).run {
|
val builder = session.criteriaBuilder
|
||||||
from(NetworkParametersEntity::class.java).run {
|
val query = builder.createQuery(NetworkParametersEntity::class.java).run {
|
||||||
orderBy(builder.desc(get<String>(NetworkParametersEntity::version.name)))
|
from(NetworkParametersEntity::class.java).run {
|
||||||
|
orderBy(builder.desc(get<String>(NetworkParametersEntity::version.name)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// We just want the last signed entry
|
||||||
|
session.createQuery(query).resultList.first()
|
||||||
}
|
}
|
||||||
// We just want the last signed entry
|
|
||||||
session.createQuery(query).resultList.first()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCurrentNetworkMapEntity(): NetworkMapEntity? = database.transaction {
|
private fun getCurrentNetworkMapEntity(): NetworkMapEntity? {
|
||||||
val builder = session.criteriaBuilder
|
return database.transaction {
|
||||||
val query = builder.createQuery(NetworkMapEntity::class.java).run {
|
val builder = session.criteriaBuilder
|
||||||
from(NetworkMapEntity::class.java).run {
|
val query = builder.createQuery(NetworkMapEntity::class.java).run {
|
||||||
where(builder.isNotNull(get<ByteArray?>(NetworkMapEntity::signature.name)))
|
from(NetworkMapEntity::class.java).run {
|
||||||
orderBy(builder.desc(get<String>(NetworkMapEntity::version.name)))
|
where(builder.isNotNull(get<ByteArray?>(NetworkMapEntity::signature.name)))
|
||||||
|
orderBy(builder.desc(get<String>(NetworkMapEntity::version.name)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// We just want the last signed entry
|
||||||
|
session.createQuery(query).resultList.firstOrNull()
|
||||||
}
|
}
|
||||||
// We just want the last signed entry
|
|
||||||
session.createQuery(query).resultList.firstOrNull()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNetworkParametersEntity(parameterHash: String): NetworkParametersEntity? = database.transaction {
|
private fun getNetworkParametersEntity(parameterHash: String): NetworkParametersEntity? {
|
||||||
singleRequestWhere(NetworkParametersEntity::class.java) { builder, path ->
|
return database.transaction {
|
||||||
builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), parameterHash)
|
singleRequestWhere(NetworkParametersEntity::class.java) { builder, path ->
|
||||||
|
builder.equal(path.get<String>(NetworkParametersEntity::parametersHash.name), parameterHash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,9 @@ import java.security.cert.CertPath
|
|||||||
*/
|
*/
|
||||||
class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeInfoStorage {
|
class PersistentNodeInfoStorage(private val database: CordaPersistence) : NodeInfoStorage {
|
||||||
override fun putNodeInfo(signedNodeInfo: SignedNodeInfo): SecureHash {
|
override fun putNodeInfo(signedNodeInfo: SignedNodeInfo): SecureHash {
|
||||||
|
val nodeInfo = signedNodeInfo.verified()
|
||||||
|
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts[0].certPath.certificates.find { CertRole.extract(it) == CertRole.NODE_CA }
|
||||||
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
|
||||||
val nodeInfo = signedNodeInfo.verified()
|
|
||||||
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts[0].certPath.certificates.find { CertRole.extract(it) == CertRole.NODE_CA }
|
|
||||||
|
|
||||||
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())
|
||||||
|
@ -49,7 +49,7 @@ class NetworkManagementServer : Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getNetworkMapService(config: NetworkMapConfig, database: CordaPersistence, signer: LocalSigner?, updateNetworkParameters: NetworkParameters?): NodeInfoWebService {
|
private fun getNetworkMapService(config: NetworkMapConfig, database: CordaPersistence, signer: LocalSigner?, updateNetworkParameters: NetworkParameters?): NodeInfoWebService {
|
||||||
val networkMapStorage = PersistentNetworkMapStorage(database)
|
val networkMapStorage = PersistentNetworkMapStorage(database, signer)
|
||||||
val nodeInfoStorage = PersistentNodeInfoStorage(database)
|
val nodeInfoStorage = PersistentNodeInfoStorage(database)
|
||||||
|
|
||||||
updateNetworkParameters?.let {
|
updateNetworkParameters?.let {
|
||||||
|
@ -8,8 +8,6 @@ import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
|||||||
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.crypto.SignedData
|
|
||||||
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.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
@ -37,9 +35,7 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
|
|
||||||
private val networkMapCache: LoadingCache<Boolean, SignedNetworkMap?> = CacheBuilder.newBuilder()
|
private val networkMapCache: LoadingCache<Boolean, SignedNetworkMap?> = CacheBuilder.newBuilder()
|
||||||
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
.expireAfterWrite(config.cacheTimeout, TimeUnit.MILLISECONDS)
|
||||||
.build(CacheLoader.from { _ ->
|
.build(CacheLoader.from { _ -> networkMapStorage.getCurrentNetworkMap() })
|
||||||
networkMapStorage.getCurrentNetworkMap()
|
|
||||||
})
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("publish")
|
@Path("publish")
|
||||||
@ -54,31 +50,27 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
// Catch exceptions thrown by signature verification.
|
// Catch exceptions thrown by signature verification.
|
||||||
when (e) {
|
when (e) {
|
||||||
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 {
|
fun getNetworkMap(): Response = createResponse(networkMapCache.get(true), addCacheTimeout = true)
|
||||||
val currentNetworkMap = networkMapCache.get(true)
|
|
||||||
return if (currentNetworkMap != null) {
|
|
||||||
Response.ok(currentNetworkMap.serialize().bytes).header("Cache-Control", "max-age=${Duration.ofMillis(config.cacheTimeout).seconds}")
|
|
||||||
} else {
|
|
||||||
status(Response.Status.NOT_FOUND)
|
|
||||||
}.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("node-info/{nodeInfoHash}")
|
@Path("node-info/{nodeInfoHash}")
|
||||||
fun getNodeInfo(@PathParam("nodeInfoHash") nodeInfoHash: String): Response {
|
fun getNodeInfo(@PathParam("nodeInfoHash") nodeInfoHash: String): Response {
|
||||||
val nodeInfo = nodeInfoStorage.getNodeInfo(SecureHash.parse(nodeInfoHash))
|
val signedNodeInfo = nodeInfoStorage.getNodeInfo(SecureHash.parse(nodeInfoHash))
|
||||||
return if (nodeInfo != null) {
|
return createResponse(signedNodeInfo)
|
||||||
ok(nodeInfo.serialize().bytes)
|
}
|
||||||
} else {
|
|
||||||
status(Response.Status.NOT_FOUND)
|
@GET
|
||||||
}.build()
|
@Path("network-parameter/{netParamsHash}") // TODO Fix path to be /network-parameters
|
||||||
|
fun getNetworkParameters(@PathParam("netParamsHash") netParamsHash: String): Response {
|
||||||
|
val signedNetParams = networkMapStorage.getSignedNetworkParameters(SecureHash.parse(netParamsHash))
|
||||||
|
return createResponse(signedNetParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@ -87,4 +79,16 @@ class NodeInfoWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
// TODO: Verify this returns IP correctly.
|
// TODO: Verify this returns IP correctly.
|
||||||
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 createResponse(payload: Any?, addCacheTimeout: Boolean = false): Response {
|
||||||
|
return if (payload != null) {
|
||||||
|
val ok = Response.ok(payload.serialize().bytes)
|
||||||
|
if (addCacheTimeout) {
|
||||||
|
ok.header("Cache-Control", "max-age=${Duration.ofMillis(config.cacheTimeout).seconds}")
|
||||||
|
}
|
||||||
|
ok
|
||||||
|
} else {
|
||||||
|
status(Response.Status.NOT_FOUND)
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ fun run(parameters: Parameters) {
|
|||||||
checkNotNull(dataSourceProperties)
|
checkNotNull(dataSourceProperties)
|
||||||
val database = configureDatabase(dataSourceProperties, databaseConfig)
|
val database = configureDatabase(dataSourceProperties, databaseConfig)
|
||||||
val csrStorage = DBSignedCertificateRequestStorage(database)
|
val csrStorage = DBSignedCertificateRequestStorage(database)
|
||||||
val networkMapStorage = PersistentNetworkMapStorage(database)
|
// TODO Remove the dependency for a local signer to make signing of network parameters work with an HSM
|
||||||
|
val networkMapStorage = PersistentNetworkMapStorage(database, localSigner = null)
|
||||||
val hsmNetworkMapSigningThread = HsmNetworkMapSigner(
|
val hsmNetworkMapSigningThread = HsmNetworkMapSigner(
|
||||||
networkMapStorage,
|
networkMapStorage,
|
||||||
networkMapCertificateName,
|
networkMapCertificateName,
|
||||||
|
@ -6,13 +6,10 @@ import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequest
|
|||||||
import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
||||||
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
|
||||||
import net.corda.nodeapi.internal.network.NotaryInfo
|
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
abstract class TestBase {
|
abstract class TestBase {
|
||||||
@Rule
|
@Rule
|
||||||
@ -48,21 +45,4 @@ abstract class TestBase {
|
|||||||
certPath = certPath
|
certPath = certPath
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove this once testNetworkParameters are updated with default parameters
|
|
||||||
protected fun createNetworkParameters(minimumPlatformVersion: Int = 1,
|
|
||||||
notaries: List<NotaryInfo> = emptyList(),
|
|
||||||
maxMessageSize: Int = 10485760,
|
|
||||||
maxTransactionSize: Int = 40000,
|
|
||||||
modifiedTime: Instant = Instant.now(),
|
|
||||||
epoch: Int = 1): NetworkParameters {
|
|
||||||
return NetworkParameters(
|
|
||||||
minimumPlatformVersion = minimumPlatformVersion,
|
|
||||||
notaries = notaries,
|
|
||||||
maxMessageSize = maxMessageSize,
|
|
||||||
maxTransactionSize = maxTransactionSize,
|
|
||||||
modifiedTime = modifiedTime,
|
|
||||||
epoch = epoch
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package com.r3.corda.networkmanage.common.persistence
|
|||||||
|
|
||||||
import com.r3.corda.networkmanage.TestBase
|
import com.r3.corda.networkmanage.TestBase
|
||||||
import com.r3.corda.networkmanage.common.utils.withCert
|
import com.r3.corda.networkmanage.common.utils.withCert
|
||||||
|
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.sign
|
import net.corda.core.crypto.sign
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
@ -23,21 +24,21 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class DBNetworkMapStorageTest : TestBase() {
|
class PersistentNetworkMapStorageTest : TestBase() {
|
||||||
private lateinit var networkMapStorage: NetworkMapStorage
|
|
||||||
private lateinit var requestStorage: CertificationRequestStorage
|
|
||||||
private lateinit var nodeInfoStorage: NodeInfoStorage
|
|
||||||
private lateinit var persistence: CordaPersistence
|
private lateinit var persistence: CordaPersistence
|
||||||
|
private lateinit var networkMapStorage: PersistentNetworkMapStorage
|
||||||
|
private lateinit var nodeInfoStorage: PersistentNodeInfoStorage
|
||||||
|
private lateinit var requestStorage: PersistentCertificateRequestStorage
|
||||||
|
|
||||||
private val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
private val rootCaKeyPair = 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 rootCaCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Corda Node Root CA", "R3 LTD", "London", "GB"), rootCaKeyPair)
|
||||||
private val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
private val intermediateCaKeyPair = 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)
|
private val intermediateCaCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCaCert, rootCaKeyPair, CordaX500Name("Corda Node Intermediate CA", "R3 LTD", "London", "GB"), intermediateCaKeyPair.public)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun startDb() {
|
fun startDb() {
|
||||||
persistence = configureDatabase(makeTestDataSourceProperties())
|
persistence = configureDatabase(makeTestDataSourceProperties())
|
||||||
networkMapStorage = PersistentNetworkMapStorage(persistence)
|
networkMapStorage = PersistentNetworkMapStorage(persistence, LocalSigner(intermediateCaKeyPair, arrayOf(intermediateCaCert.cert, rootCaCert.cert)))
|
||||||
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
nodeInfoStorage = PersistentNodeInfoStorage(persistence)
|
||||||
requestStorage = PersistentCertificateRequestStorage(persistence)
|
requestStorage = PersistentCertificateRequestStorage(persistence)
|
||||||
}
|
}
|
||||||
@ -59,7 +60,7 @@ class DBNetworkMapStorageTest : TestBase() {
|
|||||||
|
|
||||||
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash)
|
val networkMap = NetworkMap(listOf(nodeInfoHash), networkParametersHash)
|
||||||
val serializedNetworkMap = networkMap.serialize()
|
val serializedNetworkMap = networkMap.serialize()
|
||||||
val signatureData = intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)
|
val signatureData = intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert)
|
||||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@ -69,14 +70,14 @@ class DBNetworkMapStorageTest : TestBase() {
|
|||||||
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
||||||
|
|
||||||
assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature)
|
assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature)
|
||||||
assertEquals(signedNetworkMap.verified(rootCACert.cert), persistedSignedNetworkMap?.verified(rootCACert.cert))
|
assertEquals(signedNetworkMap.verified(rootCaCert.cert), persistedSignedNetworkMap?.verified(rootCaCert.cert))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getLatestNetworkParameters returns last inserted`() {
|
fun `getLatestNetworkParameters returns last inserted`() {
|
||||||
// given
|
// given
|
||||||
networkMapStorage.saveNetworkParameters(createNetworkParameters(minimumPlatformVersion = 1))
|
networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList(), minimumPlatformVersion = 1))
|
||||||
networkMapStorage.saveNetworkParameters(createNetworkParameters(minimumPlatformVersion = 2))
|
networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList(), minimumPlatformVersion = 2))
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val latest = networkMapStorage.getLatestNetworkParameters()
|
val latest = networkMapStorage.getLatestNetworkParameters()
|
||||||
@ -89,18 +90,18 @@ class DBNetworkMapStorageTest : TestBase() {
|
|||||||
fun `getCurrentNetworkParameters returns current network map parameters`() {
|
fun `getCurrentNetworkParameters returns current network map parameters`() {
|
||||||
// given
|
// given
|
||||||
// Create network parameters
|
// Create network parameters
|
||||||
val networkMapParametersHash = networkMapStorage.saveNetworkParameters(createNetworkParameters(1))
|
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
|
||||||
// Create empty network map
|
// Create empty network map
|
||||||
|
|
||||||
// Sign network map making it current network map
|
// Sign network map making it current network map
|
||||||
val networkMap = NetworkMap(emptyList(), networkMapParametersHash)
|
val networkMap = NetworkMap(emptyList(), networkParametersHash)
|
||||||
val serializedNetworkMap = networkMap.serialize()
|
val serializedNetworkMap = networkMap.serialize()
|
||||||
val signatureData = intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)
|
val signatureData = intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert)
|
||||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||||
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
networkMapStorage.saveNetworkMap(signedNetworkMap)
|
||||||
|
|
||||||
// Create new network parameters
|
// Create new network parameters
|
||||||
networkMapStorage.saveNetworkParameters(createNetworkParameters(2))
|
networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList(), minimumPlatformVersion = 2))
|
||||||
|
|
||||||
// when
|
// when
|
||||||
val result = networkMapStorage.getCurrentNetworkParameters()
|
val result = networkMapStorage.getCurrentNetworkParameters()
|
||||||
@ -109,6 +110,16 @@ class DBNetworkMapStorageTest : TestBase() {
|
|||||||
assertEquals(1, result?.minimumPlatformVersion)
|
assertEquals(1, result?.minimumPlatformVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test will probably won't be needed when we remove the explicit use of LocalSigner
|
||||||
|
@Test
|
||||||
|
fun `getSignedNetworkParameters uses the local signer to return a signed object`() {
|
||||||
|
val netParams = testNetworkParameters(emptyList())
|
||||||
|
val netParamsHash = networkMapStorage.saveNetworkParameters(netParams)
|
||||||
|
val signedNetParams = networkMapStorage.getSignedNetworkParameters(netParamsHash)
|
||||||
|
assertThat(signedNetParams?.verified()).isEqualTo(netParams)
|
||||||
|
assertThat(signedNetParams?.sig?.by).isEqualTo(intermediateCaKeyPair.public)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getValidNodeInfoHashes returns only valid and signed node info hashes`() {
|
fun `getValidNodeInfoHashes returns only valid and signed node info hashes`() {
|
||||||
// given
|
// given
|
||||||
@ -121,10 +132,10 @@ class DBNetworkMapStorageTest : TestBase() {
|
|||||||
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB)
|
val nodeInfoHashB = nodeInfoStorage.putNodeInfo(signedNodeInfoB)
|
||||||
|
|
||||||
// Create network parameters
|
// Create network parameters
|
||||||
val networkParametersHash = networkMapStorage.saveNetworkParameters(createNetworkParameters())
|
val networkParametersHash = networkMapStorage.saveNetworkParameters(testNetworkParameters(emptyList()))
|
||||||
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash)
|
val networkMap = NetworkMap(listOf(nodeInfoHashA), networkParametersHash)
|
||||||
val serializedNetworkMap = networkMap.serialize()
|
val serializedNetworkMap = networkMap.serialize()
|
||||||
val signatureData = intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)
|
val signatureData = intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert)
|
||||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, signatureData)
|
||||||
|
|
||||||
// Sign network map
|
// Sign network map
|
@ -15,6 +15,7 @@ import net.corda.nodeapi.internal.crypto.CertificateType
|
|||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -39,12 +40,12 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
fun `signNetworkMap builds and signs network map`() {
|
fun `signNetworkMap builds and signs network map`() {
|
||||||
// given
|
// given
|
||||||
val signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
|
val signedNodeInfoHashes = listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256())
|
||||||
val networkMapParameters = createNetworkParameters()
|
val networkParameters = testNetworkParameters(emptyList())
|
||||||
val serializedNetworkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256()).serialize()
|
val serializedNetworkMap = NetworkMap(signedNodeInfoHashes, SecureHash.randomSHA256()).serialize()
|
||||||
whenever(networkMapStorage.getCurrentNetworkMap())
|
whenever(networkMapStorage.getCurrentNetworkMap())
|
||||||
.thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)))
|
.thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)))
|
||||||
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes)
|
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(signedNodeInfoHashes)
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
||||||
whenever(signer.sign(any())).then {
|
whenever(signer.sign(any())).then {
|
||||||
intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert)
|
intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert)
|
||||||
}
|
}
|
||||||
@ -59,7 +60,7 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
argumentCaptor<SignedNetworkMap>().apply {
|
argumentCaptor<SignedNetworkMap>().apply {
|
||||||
verify(networkMapStorage).saveNetworkMap(capture())
|
verify(networkMapStorage).saveNetworkMap(capture())
|
||||||
val networkMap = firstValue.verified(rootCACert.cert)
|
val networkMap = firstValue.verified(rootCACert.cert)
|
||||||
assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash)
|
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
|
||||||
assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
|
assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
|
||||||
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes))
|
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes))
|
||||||
}
|
}
|
||||||
@ -68,14 +69,14 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `signNetworkMap does NOT create a new network map if there are no changes`() {
|
fun `signNetworkMap does NOT create a new network map if there are no changes`() {
|
||||||
// given
|
// given
|
||||||
val networkMapParameters = createNetworkParameters()
|
val networkParameters = testNetworkParameters(emptyList())
|
||||||
val networkMapParametersHash = networkMapParameters.serialize().bytes.sha256()
|
val networkMapParametersHash = networkParameters.serialize().bytes.sha256()
|
||||||
val networkMap = NetworkMap(emptyList(), networkMapParametersHash)
|
val networkMap = NetworkMap(emptyList(), networkMapParametersHash)
|
||||||
val serializedNetworkMap = networkMap.serialize()
|
val serializedNetworkMap = networkMap.serialize()
|
||||||
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert))
|
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert))
|
||||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
|
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(signedNetworkMap)
|
||||||
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
networkMapSigner.signNetworkMap()
|
networkMapSigner.signNetworkMap()
|
||||||
@ -88,10 +89,10 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `signNetworkMap creates a new network map if there is no current network map`() {
|
fun `signNetworkMap creates a new network map if there is no current network map`() {
|
||||||
// given
|
// given
|
||||||
val networkMapParameters = createNetworkParameters()
|
val networkParameters = testNetworkParameters(emptyList())
|
||||||
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null)
|
whenever(networkMapStorage.getCurrentNetworkMap()).thenReturn(null)
|
||||||
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
|
whenever(networkMapStorage.getNodeInfoHashes(any())).thenReturn(emptyList())
|
||||||
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkMapParameters)
|
whenever(networkMapStorage.getLatestNetworkParameters()).thenReturn(networkParameters)
|
||||||
whenever(signer.sign(any())).then {
|
whenever(signer.sign(any())).then {
|
||||||
intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert)
|
intermediateCAKey.sign(it.arguments.first() as ByteArray).withCert(intermediateCACert.cert)
|
||||||
}
|
}
|
||||||
@ -105,7 +106,7 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
argumentCaptor<SignedNetworkMap>().apply {
|
argumentCaptor<SignedNetworkMap>().apply {
|
||||||
verify(networkMapStorage).saveNetworkMap(capture())
|
verify(networkMapStorage).saveNetworkMap(capture())
|
||||||
val networkMap = firstValue.verified(rootCACert.cert)
|
val networkMap = firstValue.verified(rootCACert.cert)
|
||||||
assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash)
|
assertEquals(networkParameters.serialize().hash, networkMap.networkParameterHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,11 +8,12 @@ import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
|||||||
import com.r3.corda.networkmanage.common.utils.withCert
|
import com.r3.corda.networkmanage.common.utils.withCert
|
||||||
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
|
import com.r3.corda.networkmanage.doorman.webservice.NodeInfoWebService
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash.Companion.randomSHA256
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.SignedData
|
||||||
import net.corda.core.crypto.sign
|
import net.corda.core.crypto.sign
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.cert
|
import net.corda.core.internal.cert
|
||||||
|
import net.corda.core.internal.openHttpConnection
|
||||||
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.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
@ -21,97 +22,121 @@ import net.corda.nodeapi.internal.SignedNodeInfo
|
|||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.internal.createNodeInfoAndSigned
|
import net.corda.testing.internal.createNodeInfoAndSigned
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
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.HttpURLConnection
|
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import javax.ws.rs.core.MediaType
|
import javax.ws.rs.core.MediaType
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
|
||||||
|
|
||||||
class NodeInfoWebServiceTest {
|
class NodeInfoWebServiceTest {
|
||||||
@Rule
|
@Rule
|
||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule(true)
|
val testSerialization = SerializationEnvironmentRule(true)
|
||||||
|
|
||||||
private val testNetwotkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
private val rootCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
|
private val rootCaCert = X509Utilities.createSelfSignedCACertificate(CordaX500Name("Corda Node Root CA", "R3 LTD", "London", "GB"), rootCaKeyPair)
|
||||||
|
private val intermediateCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
|
private val intermediateCaCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCaCert, rootCaKeyPair, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCaKeyPair.public)
|
||||||
|
private val testNetworkMapConfig = NetworkMapConfig(10.seconds.toMillis(), 10.seconds.toMillis())
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `submit nodeInfo`() {
|
fun `submit nodeInfo`() {
|
||||||
// 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(), testNetwotkMapConfig)).use {
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), mock(), testNetworkMapConfig)).use {
|
||||||
it.start()
|
it.start()
|
||||||
val registerURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/publish")
|
|
||||||
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.
|
||||||
doPost(registerURL, nodeInfoAndSignature)
|
it.doPost("publish", nodeInfoAndSignature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get network map`() {
|
fun `get network map`() {
|
||||||
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
val networkMap = NetworkMap(listOf(randomSHA256(), randomSHA256()), randomSHA256())
|
||||||
val rootCACert = X509Utilities.createSelfSignedCACertificate(CordaX500Name(locality = "London", organisation = "R3 LTD", country = "GB", commonName = "Corda Node Root CA"), rootCAKey)
|
|
||||||
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
|
||||||
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCACert, rootCAKey, X500Name("CN=Corda Node Intermediate CA,L=London"), intermediateCAKey.public)
|
|
||||||
|
|
||||||
val networkMap = NetworkMap(listOf(SecureHash.randomSHA256(), SecureHash.randomSHA256()), SecureHash.randomSHA256())
|
|
||||||
val serializedNetworkMap = networkMap.serialize()
|
val serializedNetworkMap = networkMap.serialize()
|
||||||
|
val signedNetworkMap = SignedNetworkMap(serializedNetworkMap, intermediateCaKeyPair.sign(serializedNetworkMap).withCert(intermediateCaCert.cert))
|
||||||
|
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getCurrentNetworkMap() }.thenReturn(SignedNetworkMap(serializedNetworkMap, intermediateCAKey.sign(serializedNetworkMap).withCert(intermediateCACert.cert)))
|
on { getCurrentNetworkMap() }.thenReturn(signedNetworkMap)
|
||||||
}
|
}
|
||||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage, testNetwotkMapConfig)).use {
|
|
||||||
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
||||||
it.start()
|
it.start()
|
||||||
val conn = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}").openConnection() as HttpURLConnection
|
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||||
val signedNetworkMap = conn.inputStream.readBytes().deserialize<SignedNetworkMap>()
|
|
||||||
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
||||||
assertEquals(signedNetworkMap.verified(rootCACert.cert), networkMap)
|
assertEquals(signedNetworkMapResponse.verified(rootCaCert.cert), networkMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get node info`() {
|
fun `get node info`() {
|
||||||
val (nodeInfo, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
val (nodeInfo, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
||||||
|
val nodeInfoHash = nodeInfo.serialize().hash
|
||||||
val nodeInfoHash = nodeInfo.serialize().sha256()
|
|
||||||
|
|
||||||
val nodeInfoStorage: NodeInfoStorage = mock {
|
val nodeInfoStorage: NodeInfoStorage = mock {
|
||||||
on { getNodeInfo(nodeInfoHash) }.thenReturn(signedNodeInfo)
|
on { getNodeInfo(nodeInfoHash) }.thenReturn(signedNodeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock(), testNetwotkMapConfig)).use {
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(nodeInfoStorage, mock(), testNetworkMapConfig)).use {
|
||||||
it.start()
|
it.start()
|
||||||
val nodeInfoURL = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/node-info/$nodeInfoHash")
|
val nodeInfoResponse = it.doGet<SignedNodeInfo>("node-info/$nodeInfoHash")
|
||||||
val conn = nodeInfoURL.openConnection()
|
|
||||||
val nodeInfoResponse = conn.inputStream.readBytes().deserialize<SignedNodeInfo>()
|
|
||||||
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
|
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
|
||||||
assertEquals(nodeInfo, nodeInfoResponse.verified())
|
assertEquals(nodeInfo, nodeInfoResponse.verified())
|
||||||
|
|
||||||
assertFailsWith(FileNotFoundException::class) {
|
assertThatExceptionOfType(FileNotFoundException::class.java).isThrownBy {
|
||||||
URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}/${SecureHash.randomSHA256()}").openConnection().getInputStream()
|
it.doGet<SignedNodeInfo>("node-info/${randomSHA256()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doPost(url: URL, payload: ByteArray) {
|
@Test
|
||||||
val conn = url.openConnection() as HttpURLConnection
|
fun `get network parameters`() {
|
||||||
conn.doOutput = true
|
val netParams = testNetworkParameters(emptyList())
|
||||||
conn.requestMethod = "POST"
|
val serializedNetParams = netParams.serialize()
|
||||||
conn.setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
|
val signedNetParams = SignedData(serializedNetParams, intermediateCaKeyPair.sign(serializedNetParams))
|
||||||
conn.outputStream.write(payload)
|
val netParamsHash = serializedNetParams.hash
|
||||||
|
|
||||||
return try {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
conn.inputStream.bufferedReader().use { it.readLine() }
|
on { getSignedNetworkParameters(netParamsHash) }.thenReturn(signedNetParams)
|
||||||
} catch (e: IOException) {
|
}
|
||||||
throw IOException(conn.errorStream.bufferedReader().readLine(), e)
|
|
||||||
|
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NodeInfoWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
|
||||||
|
it.start()
|
||||||
|
val netParamsResponse = it.doGet<SignedData<NetworkParameters>>("network-parameter/$netParamsHash")
|
||||||
|
verify(networkMapStorage, times(1)).getSignedNetworkParameters(netParamsHash)
|
||||||
|
assertThat(netParamsResponse.verified()).isEqualTo(netParams)
|
||||||
|
assertThat(netParamsResponse.sig.by).isEqualTo(intermediateCaKeyPair.public)
|
||||||
|
|
||||||
|
assertThatExceptionOfType(FileNotFoundException::class.java).isThrownBy {
|
||||||
|
it.doGet<SignedData<NetworkParameters>>("network-parameter/${randomSHA256()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun NetworkManagementWebServer.doPost(path: String, payload: ByteArray) {
|
||||||
|
val url = URL("http://$hostAndPort/network-map/$path")
|
||||||
|
url.openHttpConnection().apply {
|
||||||
|
doOutput = true
|
||||||
|
requestMethod = "POST"
|
||||||
|
setRequestProperty("Content-Type", MediaType.APPLICATION_OCTET_STREAM)
|
||||||
|
outputStream.write(payload)
|
||||||
|
inputStream.close() // This will give us a nice IOException if the response isn't HTTP 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified T : Any> NetworkManagementWebServer.doGet(path: String): T {
|
||||||
|
val url = URL("http://$hostAndPort/network-map/$path")
|
||||||
|
return url.openHttpConnection().inputStream.use { it.readBytes().deserialize() }
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user