mirror of
https://github.com/corda/corda.git
synced 2024-12-28 16:58:55 +00:00
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:
parent
2543bb356e
commit
84398362ab
@ -141,12 +141,11 @@ class NetworkParametersUpdateTest : IntegrationTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startServer(startNetworkMap: Boolean = true): NetworkManagementServer {
|
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(
|
server.start(
|
||||||
serverAddress,
|
serverAddress,
|
||||||
CertPathAndKey(listOf(doormanCa.certificate, rootCaCert), doormanCa.keyPair.private),
|
CertPathAndKey(listOf(doormanCa.certificate, rootCaCert), doormanCa.keyPair.private),
|
||||||
DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis),
|
|
||||||
null,
|
|
||||||
if (startNetworkMap) {
|
if (startNetworkMap) {
|
||||||
NetworkMapStartParams(
|
NetworkMapStartParams(
|
||||||
LocalSigner(networkMapCa),
|
LocalSigner(networkMapCa),
|
||||||
@ -161,7 +160,11 @@ class NetworkParametersUpdateTest : IntegrationTest() {
|
|||||||
|
|
||||||
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
|
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
|
||||||
server?.close()
|
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)
|
it.processNetworkParameters(networkParametersCmd)
|
||||||
}
|
}
|
||||||
server = startServer(startNetworkMap = true)
|
server = startServer(startNetworkMap = true)
|
||||||
|
@ -73,6 +73,18 @@ class NodeRegistrationTest : IntegrationTest() {
|
|||||||
|
|
||||||
private var server: NetworkManagementServer? = null
|
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
|
@Before
|
||||||
fun init() {
|
fun init() {
|
||||||
dbName = random63BitValue().toString()
|
dbName = random63BitValue().toString()
|
||||||
@ -108,7 +120,6 @@ class NodeRegistrationTest : IntegrationTest() {
|
|||||||
},
|
},
|
||||||
rootCert = rootCaCert
|
rootCert = rootCaCert
|
||||||
)
|
)
|
||||||
|
|
||||||
internalDriver(
|
internalDriver(
|
||||||
portAllocation = portAllocation,
|
portAllocation = portAllocation,
|
||||||
compatibilityZone = compatibilityZone,
|
compatibilityZone = compatibilityZone,
|
||||||
@ -157,20 +168,10 @@ class NodeRegistrationTest : IntegrationTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startServer(startNetworkMap: Boolean = true): NetworkManagementServer {
|
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(
|
server.start(
|
||||||
serverAddress,
|
serverAddress,
|
||||||
CertPathAndKey(listOf(doormanCa.certificate, rootCaCert), doormanCa.keyPair.private),
|
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) {
|
if (startNetworkMap) {
|
||||||
NetworkMapStartParams(
|
NetworkMapStartParams(
|
||||||
LocalSigner(networkMapCa),
|
LocalSigner(networkMapCa),
|
||||||
@ -185,7 +186,7 @@ class NodeRegistrationTest : IntegrationTest() {
|
|||||||
|
|
||||||
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
|
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
|
||||||
server?.close()
|
server?.close()
|
||||||
NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true)).use {
|
NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig).use {
|
||||||
it.processNetworkParameters(networkParametersCmd)
|
it.processNetworkParameters(networkParametersCmd)
|
||||||
}
|
}
|
||||||
server = startServer(startNetworkMap = true)
|
server = startServer(startNetworkMap = true)
|
||||||
|
@ -66,6 +66,20 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
|
|||||||
|
|
||||||
private lateinit var dbName: String
|
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
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
dbName = random63BitValue().toString()
|
dbName = random63BitValue().toString()
|
||||||
@ -99,21 +113,10 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
|
|||||||
@Test
|
@Test
|
||||||
fun `Signing service signs approved CSRs`() {
|
fun `Signing service signs approved CSRs`() {
|
||||||
//Start doorman server
|
//Start doorman server
|
||||||
NetworkManagementServer(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true)).use { server ->
|
NetworkManagementServer(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig).use { server ->
|
||||||
server.start(
|
server.start(
|
||||||
hostAndPort = NetworkHostAndPort(HOST, 0),
|
hostAndPort = NetworkHostAndPort(HOST, 0),
|
||||||
csrCertPathAndKey = null,
|
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)
|
startNetworkMap = null)
|
||||||
val doormanHostAndPort = server.hostAndPort
|
val doormanHostAndPort = server.hostAndPort
|
||||||
// Start Corda network registration.
|
// Start Corda network registration.
|
||||||
|
@ -14,6 +14,7 @@ import net.corda.core.crypto.SecureHash
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
|
import java.security.PublicKey
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
|
|
||||||
data class CertificateData(val certStatus: CertificateStatus, val certPath: 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.
|
* @throws IllegalArgumentException if request is not found or not in Approved state.
|
||||||
*/
|
*/
|
||||||
fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String)
|
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 {
|
sealed class CertificateResponse {
|
||||||
|
@ -23,6 +23,7 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
|
|||||||
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
import net.corda.nodeapi.internal.persistence.DatabaseTransaction
|
||||||
import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
|
import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
|
import java.security.PublicKey
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import javax.security.auth.x500.X500Principal
|
import javax.security.auth.x500.X500Principal
|
||||||
@ -66,7 +67,6 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
|
|||||||
} catch (e: RequestValidationException) {
|
} catch (e: RequestValidationException) {
|
||||||
e.rejectMessage
|
e.rejectMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
val requestEntity = CertificateSigningRequestEntity(
|
val requestEntity = CertificateSigningRequestEntity(
|
||||||
requestId = requestId,
|
requestId = requestId,
|
||||||
legalName = legalNameOrRejectMessage as? CordaX500Name,
|
legalName = legalNameOrRejectMessage as? CordaX500Name,
|
||||||
@ -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? {
|
override fun getRequest(requestId: String): CertificateSigningRequest? {
|
||||||
return database.transaction {
|
return database.transaction {
|
||||||
findRequest(requestId)?.toCertificateSigningRequest()
|
findRequest(requestId)?.toCertificateSigningRequest()
|
||||||
|
@ -87,7 +87,7 @@ private fun caKeyGenMode(config: NetworkManagementServerConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun doormanMode(cmdLineOptions: DoormanCmdLineOptions, 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) {
|
if (cmdLineOptions.networkParametersCmd == null) {
|
||||||
// TODO: move signing to signing server.
|
// TODO: move signing to signing server.
|
||||||
@ -103,8 +103,6 @@ private fun doormanMode(cmdLineOptions: DoormanCmdLineOptions, config: NetworkMa
|
|||||||
networkManagementServer.start(
|
networkManagementServer.start(
|
||||||
config.address,
|
config.address,
|
||||||
csrAndNetworkMap?.first,
|
csrAndNetworkMap?.first,
|
||||||
config.doorman,
|
|
||||||
config.revocation,
|
|
||||||
networkMapStartParams)
|
networkMapStartParams)
|
||||||
|
|
||||||
Runtime.getRuntime().addShutdownHook(object : Thread("ShutdownHook") {
|
Runtime.getRuntime().addShutdownHook(object : Thread("ShutdownHook") {
|
||||||
|
@ -21,7 +21,6 @@ import net.corda.core.node.NetworkParameters
|
|||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
@ -31,7 +30,10 @@ import java.util.*
|
|||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
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 {
|
companion object {
|
||||||
private val logger = contextLogger()
|
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 database = configureDatabase(dataSourceProperties, databaseConfig).also { closeActions += it::close }
|
||||||
private val networkMapStorage = PersistentNetworkMapStorage(database)
|
private val networkMapStorage = PersistentNetworkMapStorage(database)
|
||||||
private val nodeInfoStorage = PersistentNodeInfoStorage(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
|
lateinit var hostAndPort: NetworkHostAndPort
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
@ -55,6 +71,8 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getNetworkMapService(config: NetworkMapConfig, signer: LocalSigner?): NetworkMapWebService {
|
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 localNetworkMapSigner = signer?.let { NetworkMapSigner(networkMapStorage, it) }
|
||||||
val latestParameters = networkMapStorage.getLatestNetworkParameters()?.networkParameters ?:
|
val latestParameters = networkMapStorage.getLatestNetworkParameters()?.networkParameters ?:
|
||||||
throw IllegalStateException("No network parameters were found. Please upload new network parameters before starting network map service")
|
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
|
closeActions += scheduledExecutor::shutdown
|
||||||
}
|
}
|
||||||
|
|
||||||
return NetworkMapWebService(nodeInfoStorage, networkMapStorage, config)
|
return NetworkMapWebService(nodeInfoStorage, networkMapStorage, csrStorage, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDoormanService(config: DoormanConfig,
|
private fun getDoormanService(config: DoormanConfig,
|
||||||
database: CordaPersistence,
|
|
||||||
csrCertPathAndKey: CertPathAndKey?,
|
csrCertPathAndKey: CertPathAndKey?,
|
||||||
serverStatus: NetworkManagementServerStatus): RegistrationWebService {
|
serverStatus: NetworkManagementServerStatus): RegistrationWebService {
|
||||||
logger.info("Starting Doorman server.")
|
logger.info("Starting Doorman server.")
|
||||||
val requestService = if (config.approveAll) {
|
csrStorage ?: throw IllegalStateException("Certificate signing request storage cannot be null when creating the doorman service.")
|
||||||
logger.warn("Doorman server is in 'Approve All' mode, this will approve all incoming certificate signing requests.")
|
|
||||||
ApproveAllCertificateSigningRequestStorage(PersistentCertificateSigningRequestStorage(database))
|
|
||||||
} else {
|
|
||||||
PersistentCertificateSigningRequestStorage(database)
|
|
||||||
}
|
|
||||||
|
|
||||||
val jiraConfig = config.jira
|
val jiraConfig = config.jira
|
||||||
val requestProcessor = if (jiraConfig != null) {
|
val requestProcessor = if (jiraConfig != null) {
|
||||||
val jiraWebAPI = AsynchronousJiraRestClientFactory().createWithBasicHttpAuthentication(URI(jiraConfig.address), jiraConfig.username, jiraConfig.password)
|
val jiraWebAPI = AsynchronousJiraRestClientFactory().createWithBasicHttpAuthentication(URI(jiraConfig.address), jiraConfig.username, jiraConfig.password)
|
||||||
val jiraClient = CsrJiraClient(jiraWebAPI, jiraConfig.projectCode)
|
val jiraClient = CsrJiraClient(jiraWebAPI, jiraConfig.projectCode)
|
||||||
JiraCsrHandler(jiraClient, requestService, DefaultCsrHandler(requestService, csrCertPathAndKey))
|
JiraCsrHandler(jiraClient, csrStorage, DefaultCsrHandler(csrStorage, csrCertPathAndKey))
|
||||||
} else {
|
} else {
|
||||||
DefaultCsrHandler(requestService, csrCertPathAndKey)
|
DefaultCsrHandler(csrStorage, csrCertPathAndKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
val scheduledExecutor = Executors.newScheduledThreadPool(1)
|
val scheduledExecutor = Executors.newScheduledThreadPool(1)
|
||||||
@ -117,17 +128,9 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getRevocationServices(config: CertificateRevocationConfig,
|
private fun getRevocationServices(config: CertificateRevocationConfig,
|
||||||
database: CordaPersistence,
|
|
||||||
csrCertPathAndKeyPair: CertPathAndKey?): Pair<CertificateRevocationRequestWebService, CertificateRevocationListWebService> {
|
csrCertPathAndKeyPair: CertPathAndKey?): Pair<CertificateRevocationRequestWebService, CertificateRevocationListWebService> {
|
||||||
logger.info("Starting Revocation server.")
|
logger.info("Starting Revocation server.")
|
||||||
val crrStorage = if (config.approveAll) {
|
crrStorage ?: throw IllegalStateException("Certificate revocation request storage cannot be null when creating the revocation service.")
|
||||||
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)
|
|
||||||
|
|
||||||
val crlHandler = csrCertPathAndKeyPair?.let {
|
val crlHandler = csrCertPathAndKeyPair?.let {
|
||||||
LocalCrlHandler(crrStorage,
|
LocalCrlHandler(crrStorage,
|
||||||
crlStorage,
|
crlStorage,
|
||||||
@ -163,17 +166,15 @@ class NetworkManagementServer(dataSourceProperties: Properties, databaseConfig:
|
|||||||
|
|
||||||
fun start(hostAndPort: NetworkHostAndPort,
|
fun start(hostAndPort: NetworkHostAndPort,
|
||||||
csrCertPathAndKey: CertPathAndKey?,
|
csrCertPathAndKey: CertPathAndKey?,
|
||||||
doormanConfig: DoormanConfig?, // TODO Doorman config shouldn't be optional as the doorman is always required to run
|
|
||||||
revocationConfig: CertificateRevocationConfig?,
|
|
||||||
startNetworkMap: NetworkMapStartParams?
|
startNetworkMap: NetworkMapStartParams?
|
||||||
) {
|
) {
|
||||||
val services = mutableListOf<Any>()
|
val services = mutableListOf<Any>()
|
||||||
val serverStatus = NetworkManagementServerStatus()
|
val serverStatus = NetworkManagementServerStatus()
|
||||||
|
|
||||||
startNetworkMap?.let { services += getNetworkMapService(it.config, it.signer) }
|
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 {
|
revocationConfig?.let {
|
||||||
val revocationServices = getRevocationServices(it, database, csrCertPathAndKey)
|
val revocationServices = getRevocationServices(it, csrCertPathAndKey)
|
||||||
services += revocationServices.first
|
services += revocationServices.first
|
||||||
services += revocationServices.second
|
services += revocationServices.second
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ package com.r3.corda.networkmanage.doorman.webservice
|
|||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine
|
import com.github.benmanes.caffeine.cache.Caffeine
|
||||||
import com.github.benmanes.caffeine.cache.LoadingCache
|
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.NetworkMapStorage
|
||||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||||
import com.r3.corda.networkmanage.doorman.NetworkMapConfig
|
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.SecureHash
|
||||||
import net.corda.core.crypto.SignedData
|
import net.corda.core.crypto.SignedData
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
|
import net.corda.core.internal.CertRole
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.deserialize
|
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.core.utilities.trace
|
||||||
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
import net.corda.nodeapi.internal.NodeInfoAndSigned
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
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 net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.InvalidKeyException
|
import java.security.InvalidKeyException
|
||||||
import java.security.SignatureException
|
import java.security.SignatureException
|
||||||
|
import java.security.cert.CertPathValidatorException
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.servlet.http.HttpServletRequest
|
import javax.servlet.http.HttpServletRequest
|
||||||
@ -46,6 +52,7 @@ import javax.ws.rs.core.Response.status
|
|||||||
@Path(NETWORK_MAP_PATH)
|
@Path(NETWORK_MAP_PATH)
|
||||||
class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
||||||
private val networkMapStorage: NetworkMapStorage,
|
private val networkMapStorage: NetworkMapStorage,
|
||||||
|
private val certificateSigningRequestStorage: CertificateSigningRequestStorage,
|
||||||
private val config: NetworkMapConfig) {
|
private val config: NetworkMapConfig) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -91,7 +98,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
logger.warn("Unable to process node-info: $nodeInfo", e)
|
logger.warn("Unable to process node-info: $nodeInfo", e)
|
||||||
when (e) {
|
when (e) {
|
||||||
is NetworkMapNotInitialisedException -> status(Response.Status.SERVICE_UNAVAILABLE).entity(e.message)
|
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)
|
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
|
||||||
@ -154,11 +161,12 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun verifyNodeInfo(nodeInfo: NodeInfo) {
|
private fun verifyNodeInfo(nodeInfo: NodeInfo) {
|
||||||
|
checkCertificates(nodeInfo)
|
||||||
checkCompositeKeys(nodeInfo)
|
checkCompositeKeys(nodeInfo)
|
||||||
val minimumPlatformVersion = currentNetworkParameters?.minimumPlatformVersion
|
val minimumPlatformVersion = currentNetworkParameters?.minimumPlatformVersion
|
||||||
?: throw NetworkMapNotInitialisedException("Network parameters have not been initialised")
|
?: throw NetworkMapNotInitialisedException("Network parameters have not been initialised")
|
||||||
if (nodeInfo.platformVersion < minimumPlatformVersion) {
|
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 parameters = checkNotNull(currentNetworkParameters) { "Network parameters not available." }
|
||||||
val notaryIdentities = parameters.notaries.map { it.identity }
|
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 {
|
private fun createResponse(payload: Any?, addCacheTimeout: Boolean = false): Response {
|
||||||
@ -184,8 +194,23 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
|
|||||||
}.build()
|
}.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 NetworkMapNotInitialisedException(message: String?) : Exception(message)
|
||||||
class InvalidPlatformVersionException(message: String?) : Exception(message)
|
class RequestException(message: String) : Exception(message)
|
||||||
|
|
||||||
private data class CachedData(val signedNetworkMap: SignedNetworkMap,
|
private data class CachedData(val signedNetworkMap: SignedNetworkMap,
|
||||||
val nodeInfoHashes: Set<SecureHash>,
|
val nodeInfoHashes: Set<SecureHash>,
|
||||||
|
@ -124,6 +124,39 @@ class PersistentCertificateRequestStorageTest : TestBase() {
|
|||||||
assertNotNull(storage.getRequest(requestId)!!.certData)
|
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
|
@Test
|
||||||
fun `sign request ignores subsequent sign requests`() {
|
fun `sign request ignores subsequent sign requests`() {
|
||||||
val (csr, nodeKeyPair) = createRequest("LegalName", certRole = CertRole.NODE_CA)
|
val (csr, nodeKeyPair) = createRequest("LegalName", certRole = CertRole.NODE_CA)
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
package com.r3.corda.networkmanage.doorman.webservice
|
package com.r3.corda.networkmanage.doorman.webservice
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.*
|
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.NetworkMapStorage
|
||||||
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
import com.r3.corda.networkmanage.common.persistence.NodeInfoStorage
|
||||||
import com.r3.corda.networkmanage.createNetworkMapEntity
|
import com.r3.corda.networkmanage.createNetworkMapEntity
|
||||||
@ -42,6 +43,7 @@ import java.io.IOException
|
|||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
class NetworkMapWebServiceTest {
|
class NetworkMapWebServiceTest {
|
||||||
@Rule
|
@Rule
|
||||||
@ -62,28 +64,54 @@ class NetworkMapWebServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `submit nodeInfo`() {
|
fun `submit nodeInfo`() {
|
||||||
|
// Create node info.
|
||||||
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
|
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity())
|
||||||
}
|
}
|
||||||
// Create node info.
|
val csrStorage: CertificateSigningRequestStorage = mock {
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"))
|
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()
|
it.start()
|
||||||
// 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.
|
||||||
it.doPost("publish", signedNodeInfo.serialize())
|
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
|
@Test
|
||||||
fun `submit old nodeInfo`() {
|
fun `submit old nodeInfo`() {
|
||||||
|
// Create node info.
|
||||||
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(networkParameters = testNetworkParameters(minimumPlatformVersion = 2)))
|
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(networkParameters = testNetworkParameters(minimumPlatformVersion = 2)))
|
||||||
}
|
}
|
||||||
// Create node info.
|
val csrStorage: CertificateSigningRequestStorage = mock {
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
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()
|
it.start()
|
||||||
assertThatThrownBy { it.doPost("publish", signedNodeInfo.serialize()) }
|
assertThatThrownBy { it.doPost("publish", signedNodeInfo.serialize()) }
|
||||||
.hasMessageStartingWith("Response Code 400: Minimum platform version is 2")
|
.hasMessageStartingWith("Response Code 400: Minimum platform version is 2")
|
||||||
@ -92,13 +120,16 @@ class NetworkMapWebServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `submit nodeInfo when no network map`() {
|
fun `submit nodeInfo when no network map`() {
|
||||||
|
// Create node info.
|
||||||
|
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getActiveNetworkMap() }.thenReturn(null)
|
on { getActiveNetworkMap() }.thenReturn(null)
|
||||||
}
|
}
|
||||||
// Create node info.
|
val csrStorage: CertificateSigningRequestStorage = mock {
|
||||||
val (_, signedNodeInfo) = createNodeInfoAndSigned(CordaX500Name("Test", "London", "GB"), platformVersion = 1)
|
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()
|
it.start()
|
||||||
assertThatThrownBy { it.doPost("publish", signedNodeInfo.serialize()) }
|
assertThatThrownBy { it.doPost("publish", signedNodeInfo.serialize()) }
|
||||||
.hasMessageStartingWith("Response Code 503: Network parameters have not been initialised")
|
.hasMessageStartingWith("Response Code 503: Network parameters have not been initialised")
|
||||||
@ -115,7 +146,7 @@ class NetworkMapWebServiceTest {
|
|||||||
on { getActiveNetworkMap() }.thenReturn(networkMapEntity)
|
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()
|
it.start()
|
||||||
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
val signedNetworkMapResponse = it.doGet<SignedNetworkMap>("")
|
||||||
verify(networkMapStorage, times(1)).getActiveNetworkMap()
|
verify(networkMapStorage, times(1)).getActiveNetworkMap()
|
||||||
@ -137,7 +168,7 @@ class NetworkMapWebServiceTest {
|
|||||||
on { getActiveNetworkMap() }.thenReturn(createNetworkMapEntity(nodeInfoHashes = listOf(nodeInfoHash)))
|
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()
|
it.start()
|
||||||
val nodeInfoResponse = it.doGet<SignedNodeInfo>("node-info/$nodeInfoHash")
|
val nodeInfoResponse = it.doGet<SignedNodeInfo>("node-info/$nodeInfoHash")
|
||||||
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
|
verify(nodeInfoStorage, times(1)).getNodeInfo(nodeInfoHash)
|
||||||
@ -159,7 +190,7 @@ class NetworkMapWebServiceTest {
|
|||||||
on { getSignedNetworkParameters(networkParametersHash) }.thenReturn(signedNetworkParameters)
|
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()
|
it.start()
|
||||||
val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash")
|
val netParamsResponse = it.doGet<SignedNetworkParameters>("network-parameters/$networkParametersHash")
|
||||||
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
|
verify(networkMapStorage, times(1)).getSignedNetworkParameters(networkParametersHash)
|
||||||
@ -181,7 +212,7 @@ class NetworkMapWebServiceTest {
|
|||||||
val networkMapStorage: NetworkMapStorage = mock {
|
val networkMapStorage: NetworkMapStorage = mock {
|
||||||
on { getSignedNetworkParameters(hash) }.thenReturn(signingCertAndKeyPair.sign(netParams))
|
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()
|
it.start()
|
||||||
val keyPair = Crypto.generateKeyPair()
|
val keyPair = Crypto.generateKeyPair()
|
||||||
val signedHash = hash.serialize().sign { keyPair.sign(it) }
|
val signedHash = hash.serialize().sign { keyPair.sign(it) }
|
||||||
|
Loading…
Reference in New Issue
Block a user