ENT-1626 Validating cert path on node info submission (#650)

* Validating cert path on node info submission

* Addressing review comments

* Refactoring user exceptions

* Changing response message.
This commit is contained in:
Michal Kit 2018-04-05 14:21:54 +01:00 committed by GitHub
parent 2543bb356e
commit 84398362ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 198 additions and 84 deletions

View File

@ -141,12 +141,11 @@ class NetworkParametersUpdateTest : IntegrationTest() {
}
private fun startServer(startNetworkMap: Boolean = true): NetworkManagementServer {
val server = NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true))
val doormanConfig = DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis)
val server = NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true), doormanConfig, null)
server.start(
serverAddress,
CertPathAndKey(listOf(doormanCa.certificate, rootCaCert), doormanCa.keyPair.private),
DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis),
null,
if (startNetworkMap) {
NetworkMapStartParams(
LocalSigner(networkMapCa),
@ -161,7 +160,11 @@ class NetworkParametersUpdateTest : IntegrationTest() {
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
server?.close()
NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true)).use {
NetworkManagementServer(
makeTestDataSourceProperties(dbName),
DatabaseConfig(runMigration = true),
DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis),
null).use {
it.processNetworkParameters(networkParametersCmd)
}
server = startServer(startNetworkMap = true)

View File

@ -73,6 +73,18 @@ class NodeRegistrationTest : IntegrationTest() {
private var server: NetworkManagementServer? = null
private val doormanConfig: DoormanConfig get() = DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis)
private val revocationConfig: CertificateRevocationConfig
get() = CertificateRevocationConfig(
approveAll = true,
jira = null,
approveInterval = timeoutMillis,
crlCacheTimeout = timeoutMillis,
localSigning = CertificateRevocationConfig.LocalSigning(
crlEndpoint = URL("http://test.com/crl"),
crlUpdateInterval = timeoutMillis)
)
@Before
fun init() {
dbName = random63BitValue().toString()
@ -108,7 +120,6 @@ class NodeRegistrationTest : IntegrationTest() {
},
rootCert = rootCaCert
)
internalDriver(
portAllocation = portAllocation,
compatibilityZone = compatibilityZone,
@ -157,20 +168,10 @@ class NodeRegistrationTest : IntegrationTest() {
}
private fun startServer(startNetworkMap: Boolean = true): NetworkManagementServer {
val server = NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true))
val server = NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig)
server.start(
serverAddress,
CertPathAndKey(listOf(doormanCa.certificate, rootCaCert), doormanCa.keyPair.private),
DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis),
CertificateRevocationConfig(
approveAll = true,
jira = null,
approveInterval = timeoutMillis,
crlCacheTimeout = timeoutMillis,
localSigning = CertificateRevocationConfig.LocalSigning(
crlEndpoint = URL("http://test.com/crl"),
crlUpdateInterval = timeoutMillis)
),
if (startNetworkMap) {
NetworkMapStartParams(
LocalSigner(networkMapCa),
@ -185,7 +186,7 @@ class NodeRegistrationTest : IntegrationTest() {
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
server?.close()
NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true)).use {
NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig).use {
it.processNetworkParameters(networkParametersCmd)
}
server = startServer(startNetworkMap = true)

View File

@ -66,6 +66,20 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
private lateinit var dbName: String
private val doormanConfig: DoormanConfig get() = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jira = null)
private val revocationConfig: CertificateRevocationConfig
get() = CertificateRevocationConfig(
approveAll = true,
jira = null,
crlCacheTimeout = 30.minutes.toMillis(),
approveInterval = 10.minutes.toMillis(),
localSigning = CertificateRevocationConfig.LocalSigning(
crlEndpoint = URL("http://test.com/crl"),
crlUpdateInterval = 2.hours.toMillis()
)
)
@Before
fun setUp() {
dbName = random63BitValue().toString()
@ -99,21 +113,10 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
@Test
fun `Signing service signs approved CSRs`() {
//Start doorman server
NetworkManagementServer(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true)).use { server ->
NetworkManagementServer(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig).use { server ->
server.start(
hostAndPort = NetworkHostAndPort(HOST, 0),
csrCertPathAndKey = null,
doormanConfig = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jira = null),
revocationConfig = CertificateRevocationConfig(
approveAll = true,
jira = null,
crlCacheTimeout = 30.minutes.toMillis(),
approveInterval = 10.minutes.toMillis(),
localSigning = CertificateRevocationConfig.LocalSigning(
crlEndpoint = URL("http://test.com/crl"),
crlUpdateInterval = 2.hours.toMillis()
)
),
startNetworkMap = null)
val doormanHostAndPort = server.hostAndPort
// Start Corda network registration.

View File

@ -14,6 +14,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.identity.CordaX500Name
import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.pkcs.PKCS10CertificationRequest
import java.security.PublicKey
import java.security.cert.CertPath
data class CertificateData(val certStatus: CertificateStatus, val certPath: CertPath)
@ -83,6 +84,14 @@ interface CertificateSigningRequestStorage {
* @throws IllegalArgumentException if request is not found or not in Approved state.
*/
fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String)
/**
* Retrieves the certificate path for the given public key hash if such exists and its certificate is considered to be valid.
*
* @param publicKey public key corresponding to the certificate being searched.
* @return certificate path for the given public key hash or null if such certificate does not exist or is not valid.
*/
fun getValidCertificatePath(publicKey: PublicKey): CertPath?
}
sealed class CertificateResponse {

View File

@ -23,6 +23,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
import org.bouncycastle.pkcs.PKCS10CertificationRequest
import java.security.PublicKey
import java.security.cert.CertPath
import java.time.Instant
import javax.security.auth.x500.X500Principal
@ -66,15 +67,14 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
} catch (e: RequestValidationException) {
e.rejectMessage
}
val requestEntity = CertificateSigningRequestEntity(
requestId = requestId,
legalName = legalNameOrRejectMessage as? CordaX500Name,
publicKeyHash = toSupportedPublicKey(request.subjectPublicKeyInfo).hashString(),
request = request,
remark = legalNameOrRejectMessage as? String,
modifiedBy = CertificateSigningRequestStorage.DOORMAN_SIGNATURE,
status = if (legalNameOrRejectMessage is CordaX500Name) RequestStatus.NEW else RequestStatus.REJECTED
requestId = requestId,
legalName = legalNameOrRejectMessage as? CordaX500Name,
publicKeyHash = toSupportedPublicKey(request.subjectPublicKeyInfo).hashString(),
request = request,
remark = legalNameOrRejectMessage as? String,
modifiedBy = CertificateSigningRequestStorage.DOORMAN_SIGNATURE,
status = if (legalNameOrRejectMessage is CordaX500Name) RequestStatus.NEW else RequestStatus.REJECTED
)
session.save(requestEntity)
}
@ -131,6 +131,16 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
}
}
override fun getValidCertificatePath(publicKey: PublicKey): CertPath? {
return database.transaction {
session.createQuery(
"select a.certificateData.certPath from ${CertificateSigningRequestEntity::class.java.name} a " +
"where a.publicKeyHash = :publicKeyHash and a.status = 'DONE' and a.certificateData.certificateStatus = 'VALID'", CertPath::class.java)
.setParameter("publicKeyHash", publicKey.hashString())
.uniqueResult()
}
}
override fun getRequest(requestId: String): CertificateSigningRequest? {
return database.transaction {
findRequest(requestId)?.toCertificateSigningRequest()

View File

@ -87,7 +87,7 @@ private fun caKeyGenMode(config: NetworkManagementServerConfig) {
}
private fun doormanMode(cmdLineOptions: DoormanCmdLineOptions, config: NetworkManagementServerConfig) {
val networkManagementServer = NetworkManagementServer(config.dataSourceProperties, config.database)
val networkManagementServer = NetworkManagementServer(config.dataSourceProperties, config.database, config.doorman, config.revocation)
if (cmdLineOptions.networkParametersCmd == null) {
// TODO: move signing to signing server.
@ -103,8 +103,6 @@ private fun doormanMode(cmdLineOptions: DoormanCmdLineOptions, config: NetworkMa
networkManagementServer.start(
config.address,
csrAndNetworkMap?.first,
config.doorman,
config.revocation,
networkMapStartParams)
Runtime.getRuntime().addShutdownHook(object : Thread("ShutdownHook") {

View File

@ -21,7 +21,6 @@ import net.corda.core.node.NetworkParameters
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import java.io.Closeable
import java.net.URI
@ -31,7 +30,10 @@ import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig: DatabaseConfig) : Closeable {
class NetworkManagementServer(dataSourceProperties: Properties,
databaseConfig: DatabaseConfig,
private val doormanConfig: DoormanConfig?, // TODO Doorman config shouldn't be optional as the doorman is always required to run
private val revocationConfig: CertificateRevocationConfig?) : Closeable {
companion object {
private val logger = contextLogger()
}
@ -40,7 +42,21 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
private val database = configureDatabase(dataSourceProperties, databaseConfig).also { closeActions += it::close }
private val networkMapStorage = PersistentNetworkMapStorage(database)
private val nodeInfoStorage = PersistentNodeInfoStorage(database)
private val crlStorage = PersistentCertificateRevocationListStorage(database)
private val csrStorage = doormanConfig?.let {
if (it.approveAll) {
ApproveAllCertificateSigningRequestStorage(PersistentCertificateSigningRequestStorage(database))
} else {
PersistentCertificateSigningRequestStorage(database)
}
}
private val crrStorage = revocationConfig?.let {
if (it.approveAll) {
ApproveAllCertificateRevocationRequestStorage(PersistentCertificateRevocationRequestStorage(database))
} else {
PersistentCertificateRevocationRequestStorage(database)
}
}
lateinit var hostAndPort: NetworkHostAndPort
override fun close() {
@ -55,6 +71,8 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
}
private fun getNetworkMapService(config: NetworkMapConfig, signer: LocalSigner?): NetworkMapWebService {
logger.info("Starting Network Map server.")
csrStorage ?: throw IllegalStateException("Certificate signing request storage cannot be null when creating the network map service.")
val localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) }
val latestParameters = networkMapStorage.getLatestNetworkParameters()?.networkParameters ?:
throw IllegalStateException("No network parameters were found. Please upload new network parameters before starting network map service")
@ -75,28 +93,21 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
closeActions += scheduledExecutor::shutdown
}
return NetworkMapWebService(nodeInfoStorage, networkMapStorage, config)
return NetworkMapWebService(nodeInfoStorage, networkMapStorage, csrStorage, config)
}
private fun getDoormanService(config: DoormanConfig,
database: CordaPersistence,
csrCertPathAndKey: CertPathAndKey?,
serverStatus: NetworkManagementServerStatus): RegistrationWebService {
logger.info("Starting Doorman server.")
val requestService = if (config.approveAll) {
logger.warn("Doorman server is in 'Approve All' mode, this will approve all incoming certificate signing requests.")
ApproveAllCertificateSigningRequestStorage(PersistentCertificateSigningRequestStorage(database))
} else {
PersistentCertificateSigningRequestStorage(database)
}
csrStorage ?: throw IllegalStateException("Certificate signing request storage cannot be null when creating the doorman service.")
val jiraConfig = config.jira
val requestProcessor = if (jiraConfig != null) {
val jiraWebAPI = AsynchronousJiraRestClientFactory().createWithBasicHttpAuthentication(URI(jiraConfig.address), jiraConfig.username, jiraConfig.password)
val jiraClient = CsrJiraClient(jiraWebAPI, jiraConfig.projectCode)
JiraCsrHandler(jiraClient, requestService, DefaultCsrHandler(requestService, csrCertPathAndKey))
JiraCsrHandler(jiraClient, csrStorage, DefaultCsrHandler(csrStorage, csrCertPathAndKey))
} else {
DefaultCsrHandler(requestService, csrCertPathAndKey)
DefaultCsrHandler(csrStorage, csrCertPathAndKey)
}
val scheduledExecutor = Executors.newScheduledThreadPool(1)
@ -117,17 +128,9 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
}
private fun getRevocationServices(config: CertificateRevocationConfig,
database: CordaPersistence,
csrCertPathAndKeyPair: CertPathAndKey?): Pair<CertificateRevocationRequestWebService, CertificateRevocationListWebService> {
logger.info("Starting Revocation server.")
val crrStorage = if (config.approveAll) {
logger.warn("Revocation server is in 'Approve All' mode, this will approve all incoming certificate signing requests.")
ApproveAllCertificateRevocationRequestStorage(PersistentCertificateRevocationRequestStorage(database))
} else {
PersistentCertificateRevocationRequestStorage(database)
}
val crlStorage = PersistentCertificateRevocationListStorage(database)
crrStorage ?: throw IllegalStateException("Certificate revocation request storage cannot be null when creating the revocation service.")
val crlHandler = csrCertPathAndKeyPair?.let {
LocalCrlHandler(crrStorage,
crlStorage,
@ -163,17 +166,15 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
fun start(hostAndPort: NetworkHostAndPort,
csrCertPathAndKey: CertPathAndKey?,
doormanConfig: DoormanConfig?, // TODO Doorman config shouldn't be optional as the doorman is always required to run
revocationConfig: CertificateRevocationConfig?,
startNetworkMap: NetworkMapStartParams?
) {
val services = mutableListOf<Any>()
val serverStatus = NetworkManagementServerStatus()
startNetworkMap?.let { services += getNetworkMapService(it.config, it.signer) }
doormanConfig?.let { services += getDoormanService(it, database, csrCertPathAndKey, serverStatus) }
doormanConfig?.let { services += getDoormanService(it, csrCertPathAndKey, serverStatus) }
revocationConfig?.let {
val revocationServices = getRevocationServices(it, database, csrCertPathAndKey)
val revocationServices = getRevocationServices(it, csrCertPathAndKey)
services += revocationServices.first
services += revocationServices.second
}

View File

@ -12,6 +12,7 @@ package com.r3.corda.networkmanage.doorman.webservice
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.LoadingCache
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequestStorage
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
@ -20,6 +21,7 @@ import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sha256
import net.corda.core.internal.CertRole
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.deserialize
@ -29,10 +31,14 @@ import net.corda.core.utilities.debug
import net.corda.core.utilities.trace
import net.corda.nodeapi.internal.NodeInfoAndSigned
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.crypto.X509Utilities.validateCertPath
import net.corda.nodeapi.internal.crypto.x509
import net.corda.nodeapi.internal.crypto.x509Certificates
import net.corda.nodeapi.internal.network.SignedNetworkMap
import java.io.InputStream
import java.security.InvalidKeyException
import java.security.SignatureException
import java.security.cert.CertPathValidatorException
import java.time.Duration
import java.util.concurrent.TimeUnit
import javax.servlet.http.HttpServletRequest
@ -46,6 +52,7 @@ import javax.ws.rs.core.Response.status
@Path(NETWORK_MAP_PATH)
class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
private val networkMapStorage: NetworkMapStorage,
private val certificateSigningRequestStorage: CertificateSigningRequestStorage,
private val config: NetworkMapConfig) {
companion object {
@ -91,7 +98,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
logger.warn("Unable to process node-info: $nodeInfo", e)
when (e) {
is NetworkMapNotInitialisedException -> status(Response.Status.SERVICE_UNAVAILABLE).entity(e.message)
is InvalidPlatformVersionException -> status(Response.Status.BAD_REQUEST).entity(e.message)
is RequestException -> status(Response.Status.BAD_REQUEST).entity(e.message)
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.
else -> throw e
@ -154,11 +161,12 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
}
private fun verifyNodeInfo(nodeInfo: NodeInfo) {
checkCertificates(nodeInfo)
checkCompositeKeys(nodeInfo)
val minimumPlatformVersion = currentNetworkParameters?.minimumPlatformVersion
?: throw NetworkMapNotInitialisedException("Network parameters have not been initialised")
if (nodeInfo.platformVersion < minimumPlatformVersion) {
throw InvalidPlatformVersionException("Minimum platform version is $minimumPlatformVersion")
throw RequestException("Minimum platform version is $minimumPlatformVersion")
}
}
@ -169,7 +177,9 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
}
val parameters = checkNotNull(currentNetworkParameters) { "Network parameters not available." }
val notaryIdentities = parameters.notaries.map { it.identity }
require(notaryIdentities.containsAll(compositeKeyIdentities)) { "A composite key needs to belong to a notary." }
if (!notaryIdentities.containsAll(compositeKeyIdentities)) {
throw RequestException("A composite key needs to belong to a notary.")
}
}
private fun createResponse(payload: Any?, addCacheTimeout: Boolean = false): Response {
@ -184,8 +194,23 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
}.build()
}
private fun checkCertificates(nodeInfo: NodeInfo) {
val nodeCaCert = nodeInfo.legalIdentitiesAndCerts.first().certPath.x509Certificates.find { CertRole.extract(it) == CertRole.NODE_CA }
nodeCaCert ?: throw RequestException("The node certificate path does not contain the node CA certificate type in it.")
val nodeCertPath = certificateSigningRequestStorage.getValidCertificatePath(nodeCaCert.publicKey)
nodeCertPath ?: throw RequestException("Node certificate is either no longer valid or was never registered.")
val rootCert = nodeCertPath.certificates.last().x509
try {
nodeInfo.legalIdentitiesAndCerts.forEach {
validateCertPath(rootCert, it.certPath)
}
} catch (e: CertPathValidatorException) {
throw RequestException("Invalid certificate path.")
}
}
class NetworkMapNotInitialisedException(message: String?) : Exception(message)
class InvalidPlatformVersionException(message: String?) : Exception(message)
class RequestException(message: String) : Exception(message)
private data class CachedData(val signedNetworkMap: SignedNetworkMap,
val nodeInfoHashes: Set<SecureHash>,

View File

@ -124,6 +124,39 @@ class PersistentCertificateRequestStorageTest : TestBase() {
assertNotNull(storage.getRequest(requestId)!!.certData)
}
@Test
fun `get valid certificate path returns correct value`() {
// given
val (csr, nodeKeyPair) = createRequest("LegalName", certRole = CertRole.NODE_CA)
val requestId = storage.saveRequest(csr)
storage.markRequestTicketCreated(requestId)
storage.approveRequest(requestId, DOORMAN_SIGNATURE)
val certPath = generateSignedCertPath(csr, nodeKeyPair)
storage.putCertificatePath(
requestId,
certPath,
DOORMAN_SIGNATURE
)
// when
val storedCertPath = storage.getValidCertificatePath(nodeKeyPair.public)
// then
assertEquals(certPath, storedCertPath)
}
@Test
fun `get valid certificate path returns null if the certificate path cannot be found`() {
// given
val (_, nodeKeyPair) = createRequest("LegalName", certRole = CertRole.NODE_CA)
// when
val storedCertPath = storage.getValidCertificatePath(nodeKeyPair.public)
// then
assertNull(storedCertPath)
}
@Test
fun `sign request ignores subsequent sign requests`() {
val (csr, nodeKeyPair) = createRequest("LegalName", certRole = CertRole.NODE_CA)

View File

@ -11,6 +11,7 @@
package com.r3.corda.networkmanage.doorman.webservice
import com.nhaarman.mockito_kotlin.*
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequestStorage
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
import com.r3.corda.networkmanage.createNetworkMapEntity
@ -42,6 +43,7 @@ import java.io.IOException
import java.net.URL
import java.security.cert.X509Certificate
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class NetworkMapWebServiceTest {
@Rule
@ -62,28 +64,54 @@ class NetworkMapWebServiceTest {
@Test
fun `submit nodeInfo`() {
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
val networkMapStorage: NetworkMapStorage = mock {
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
}
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
val csrStorage: CertificateSigningRequestStorage = mock {
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, csrStorage, testNetworkMapConfig)).use {
it.start()
// Post node info and signature to doorman, this should pass without any exception.
it.doPost("publish", signedNodeInfo.serialize())
}
}
@Test
fun `submit nodeInfo with an unknown public key fails`() {
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
val networkMapStorage: NetworkMapStorage = mock {
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
}
val csrStorage: CertificateSigningRequestStorage = mock {
on { getValidCertificatePath(any()) }.thenReturn(null)
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, csrStorage, testNetworkMapConfig)).use {
it.start()
// Post node info and signature to doorman, this should pass without any exception.
assertFailsWith<IOException>("Response Code 400") {
it.doPost("publish", signedNodeInfo.serialize())
}
}
}
@Test
fun `submit old nodeInfo`() {
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
val networkMapStorage: NetworkMapStorage = mock {
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(networkParameters = testNetworkParameters(minimumPlatformVersion = 2)))
}
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
val csrStorage: CertificateSigningRequestStorage = mock {
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, csrStorage, testNetworkMapConfig)).use {
it.start()
assertThatThrownBy { it.doPost("publish", signedNodeInfo.serialize()) }
.hasMessageStartingWith("Response Code 400: Minimum platform version is 2")
@ -92,13 +120,16 @@ class NetworkMapWebServiceTest {
@Test
fun `submit nodeInfo when no network map`() {
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
val networkMapStorage: NetworkMapStorage = mock {
on { getActiveNetworkMap() }.thenReturn(null)
}
// Create node info.
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
val csrStorage: CertificateSigningRequestStorage = mock {
on { getValidCertificatePath(any()) }.thenReturn(signedNodeInfo.verified().legalIdentitiesAndCerts.first().certPath)
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, csrStorage, testNetworkMapConfig)).use {
it.start()
assertThatThrownBy { it.doPost("publish", signedNodeInfo.serialize()) }
.hasMessageStartingWith("Response Code 503: Network parameters have not been initialised")
@ -115,7 +146,7 @@ class NetworkMapWebServiceTest {
on { getActiveNetworkMap() }.thenReturn(networkMapEntity)
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, mock(), testNetworkMapConfig)).use {
it.start()
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
verify(networkMapStorage, times(1)).getActiveNetworkMap()
@ -137,7 +168,7 @@ class NetworkMapWebServiceTest {
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(nodeInfoHashes = listOf(nodeInfoHash)))
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, testNetworkMapConfig)).use {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, mock(), testNetworkMapConfig)).use {
it.start()
val nodeInfoResponse = it.doGet<SignedNodeInfo>("node-info/$nodeInfoHash")
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
@ -159,7 +190,7 @@ class NetworkMapWebServiceTest {
on { getSignedNetworkParameters(networkParametersHash) }.thenReturn(signedNetworkParameters)
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, testNetworkMapConfig)).use {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(mock(), networkMapStorage, mock(), testNetworkMapConfig)).use {
it.start()
val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash")
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
@ -181,7 +212,7 @@ class NetworkMapWebServiceTest {
val networkMapStorage: NetworkMapStorage = mock {
on { getSignedNetworkParameters(hash) }.thenReturn(signingCertAndKeyPair.sign(netParams))
}
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, testNetworkMapConfig)).use {
NetworkManagementWebServer(NetworkHostAndPort("localhost", 0), NetworkMapWebService(nodeInfoStorage, networkMapStorage, mock(), testNetworkMapConfig)).use {
it.start()
val keyPair = Crypto.generateKeyPair()
val signedHash = hash.serialize().sign { keyPair.sign(it) }