ENT-1608: Check that notary identities are registered (#799)

Check that notary identities are registered

On loading new parameteres check that provieded notary identities were
registered by doorman.
Refactor of NetworkParameters loading code in network-management.
This commit is contained in:
Katarzyna Streich 2018-05-03 11:09:11 +01:00 committed by GitHub
parent c3429cc621
commit 2e1cee00f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 265 additions and 130 deletions

View File

@ -61,17 +61,22 @@ It is ready to be included into the certificate revocation list.
* The signed list is serialised and stored in the networking service database ready to be served. Also, all approved requests become revoked now.
Signing Network Map
-------------------
Signing Network Map and Network Parameters
------------------------------------------
* The networking service receives a new (or updated) node info.
* Periodically (the time interval is pre-configured at the deployment time), the signing service fetches from the database current network map, all node info objects with valid certificates and current network parameters.
* Periodically (the time interval is pre-configured at the deployment time), the signing service fetches from the database all information needed to construct new network map, which includes:
- current network map,
- all node info objects with valid certificates,
- current network parameters
- information on parameters update (if exists).
* A new network map object is created out of the fetched data.
* If the new network map hash does not differ from the current network map hash, then nothing happens and current network map remains unchanged.
* If they are different, then the newly created network map object is serialized using the Corda AMQP serialisation format and signed by the dedicated intermediate certificate stored in HSM.
The same process applies to network parameters which need to be signed separately.
* Once signed, the new network map data is stored in the networking service database and available for nodes to retrieve when they next poll for the network map.

View File

@ -175,7 +175,7 @@ class NetworkParametersUpdateTest : IntegrationTest() {
DatabaseConfig(runMigration = true),
DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis),
null).use {
it.processNetworkParameters(networkParametersCmd)
it.netParamsUpdateHandler.processNetworkParameters(networkParametersCmd)
}
server = startServer(startNetworkMap = true)
// Wait for server to process the parameters update and for the nodes to poll again

View File

@ -191,7 +191,7 @@ class NodeRegistrationTest : IntegrationTest() {
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
server?.close()
NetworkManagementServer(makeTestDataSourceProperties(DOORMAN_DB_NAME, dbNamePostfix, fallBackConfigSupplier = ::networkMapInMemoryH2DataSourceConfig), makeTestDatabaseProperties(DOORMAN_DB_NAME), doormanConfig, revocationConfig).use {
it.processNetworkParameters(networkParametersCmd)
it.netParamsUpdateHandler.processNetworkParameters(networkParametersCmd)
}
server = startServer(startNetworkMap = true)
// Wait for server to process the parameters update and for the nodes to poll again

View File

@ -2,15 +2,12 @@ package com.r3.corda.networkmanage.doorman
import com.google.common.primitives.Booleans
import com.r3.corda.networkmanage.common.utils.ArgsParser
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigParseOptions
import joptsimple.OptionSet
import joptsimple.util.EnumConverter
import joptsimple.util.PathConverter
import joptsimple.util.PathProperties
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NotaryInfo
import net.corda.nodeapi.internal.config.parseAs
import java.nio.file.Path
import java.time.Instant
@ -44,21 +41,18 @@ class DoormanArgsParser : ArgsParser<DoormanCmdLineOptions>() {
require(Booleans.countTrue(setNetworkParametersFile != null, flagDay, cancelUpdate) <= 1) {
"Only one of $setNetworkParametersArg, $flagDay and $cancelUpdate can be specified"
}
val networkParametersOption = when {
setNetworkParametersFile != null -> NetworkParametersCmd.Set.fromFile(setNetworkParametersFile)
flagDay -> NetworkParametersCmd.FlagDay
cancelUpdate -> NetworkParametersCmd.CancelUpdate
else -> null
}
val trustStorePassword = optionSet.valueOf(trustStorePasswordArg)
return DoormanCmdLineOptions(configFile, mode, networkParametersOption, trustStorePassword)
return DoormanCmdLineOptions(configFile, mode, trustStorePassword, setNetworkParametersFile, flagDay, cancelUpdate)
}
}
data class DoormanCmdLineOptions(val configFile: Path,
val mode: Mode,
val networkParametersCmd: NetworkParametersCmd?,
val trustStorePassword: String?) {
val trustStorePassword: String?,
val setNetworkParametersFile: Path?,
val flagDay: Boolean,
val cancelUpdate: Boolean
) {
init {
// Make sure trust store password is only specified in root keygen mode.
if (mode != Mode.ROOT_KEYGEN) {
@ -76,20 +70,17 @@ sealed class NetworkParametersCmd {
val notaries: List<NotaryInfo>,
val maxMessageSize: Int,
val maxTransactionSize: Int,
val parametersUpdate: ParametersUpdateConfig?) : NetworkParametersCmd() {
val parametersUpdate: ParametersUpdateConfig?
) : NetworkParametersCmd() {
companion object {
fun fromFile(file: Path): Set {
return ConfigFactory.parseFile(file.toFile(), ConfigParseOptions.defaults())
.parseAs<NetworkParametersConfig>()
.let {
Set(
it.minimumPlatformVersion,
it.notaries.map { it.toNotaryInfo() },
it.maxMessageSize,
it.maxTransactionSize,
it.parametersUpdate
)
}
fun fromConfig(config: NetworkParametersConfig): Set {
return Set(
config.minimumPlatformVersion,
config.notaries.map { it.toNotaryInfo() },
config.maxMessageSize,
config.maxTransactionSize,
config.parametersUpdate
)
}
}

View File

@ -13,7 +13,6 @@ package com.r3.corda.networkmanage.doorman
import com.jcabi.manifests.Manifests
import com.r3.corda.networkmanage.common.utils.*
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.crypto.CordaSecurityProvider
import net.corda.core.crypto.Crypto
import net.corda.core.internal.exists
import net.corda.nodeapi.internal.crypto.X509KeyStore
@ -85,7 +84,14 @@ private fun caKeyGenMode(config: NetworkManagementServerConfig) {
private fun doormanMode(cmdLineOptions: DoormanCmdLineOptions, config: NetworkManagementServerConfig) {
val networkManagementServer = NetworkManagementServer(config.dataSourceProperties, config.database, config.doorman, config.revocation)
if (cmdLineOptions.networkParametersCmd == null) {
val networkParametersCmd = when {
cmdLineOptions.setNetworkParametersFile != null ->
networkManagementServer.netParamsUpdateHandler.loadParametersFromFile(cmdLineOptions.setNetworkParametersFile)
cmdLineOptions.flagDay -> NetworkParametersCmd.FlagDay
cmdLineOptions.cancelUpdate -> NetworkParametersCmd.CancelUpdate
else -> null
}
if (networkParametersCmd == null) {
// TODO: move signing to signing server.
val csrAndNetworkMap = processKeyStore(config)
if (csrAndNetworkMap != null) {
@ -108,7 +114,7 @@ private fun doormanMode(cmdLineOptions: DoormanCmdLineOptions, config: NetworkMa
})
} else {
networkManagementServer.use {
it.processNetworkParameters(cmdLineOptions.networkParametersCmd)
it.netParamsUpdateHandler.processNetworkParameters(networkParametersCmd)
}
}
}

View File

@ -12,12 +12,10 @@ package com.r3.corda.networkmanage.doorman
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory
import com.r3.corda.networkmanage.common.persistence.*
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus
import com.r3.corda.networkmanage.common.signer.NetworkMapSigner
import com.r3.corda.networkmanage.common.utils.CertPathAndKey
import com.r3.corda.networkmanage.doorman.signer.*
import com.r3.corda.networkmanage.doorman.webservice.*
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
@ -42,6 +40,14 @@ class NetworkManagementServer(dataSourceProperties: Properties,
private val database = configureDatabase(dataSourceProperties, databaseConfig).also { closeActions += it::close }
private val networkMapStorage = PersistentNetworkMapStorage(database)
private val nodeInfoStorage = PersistentNodeInfoStorage(database)
private val csrStorage = PersistentCertificateSigningRequestStorage(database).let {
if (doormanConfig?.approveAll ?: false) {
ApproveAllCertificateSigningRequestStorage(it)
} else {
it
}
}
val netParamsUpdateHandler = ParametersUpdateHandler(csrStorage, networkMapStorage)
lateinit var hostAndPort: NetworkHostAndPort
@ -84,14 +90,6 @@ class NetworkManagementServer(dataSourceProperties: Properties,
serverStatus: NetworkManagementServerStatus): RegistrationWebService {
logger.info("Starting Doorman server.")
val csrStorage = PersistentCertificateSigningRequestStorage(database).let {
if (config.approveAll) {
ApproveAllCertificateSigningRequestStorage(it)
} else {
it
}
}
val jiraConfig = config.jira
val requestProcessor = if (jiraConfig != null) {
val jiraWebAPI = AsynchronousJiraRestClientFactory().createWithBasicHttpAuthentication(URI(jiraConfig.address), jiraConfig.username, jiraConfig.password)
@ -189,86 +187,4 @@ class NetworkManagementServer(dataSourceProperties: Properties,
closeActions += webServer::close
this.hostAndPort = webServer.hostAndPort
}
fun processNetworkParameters(networkParametersCmd: NetworkParametersCmd) {
when (networkParametersCmd) {
is NetworkParametersCmd.Set -> handleSetNetworkParameters(networkParametersCmd)
NetworkParametersCmd.FlagDay -> handleFlagDay()
NetworkParametersCmd.CancelUpdate -> handleCancelUpdate()
}
}
private fun handleSetNetworkParameters(setNetParams: NetworkParametersCmd.Set) {
logger.info("maxMessageSize is not currently wired in the nodes")
val activeNetParams = networkMapStorage.getNetworkMaps().publicNetworkMap?.networkParameters?.networkParameters
if (activeNetParams == null) {
require(setNetParams.parametersUpdate == null) {
"'parametersUpdate' specified in network parameters file but there are no network parameters to update"
}
val initialNetParams = setNetParams.toNetworkParameters(modifiedTime = Instant.now(), epoch = 1)
logger.info("Saving initial network parameters to be signed:\n$initialNetParams")
networkMapStorage.saveNetworkParameters(initialNetParams, null)
println("Saved initial network parameters to be signed:\n$initialNetParams")
} else {
val parametersUpdate = requireNotNull(setNetParams.parametersUpdate) {
"'parametersUpdate' not specified in network parameters file but there is already an active set of network parameters"
}
setNetParams.checkCompatibility(activeNetParams)
val latestNetParams = checkNotNull(networkMapStorage.getLatestNetworkParameters()?.networkParameters) {
"Something has gone wrong! We have an active set of network parameters ($activeNetParams) but apparently no latest network parameters!"
}
// It's not necessary that latestNetParams is the current active network parameters. It can be the network
// parameters from a previous update attempt which has't activated yet. We still take the epoch value for this
// new set from latestNetParams to make sure the advertised update attempts have incrementing epochs.
// This has the implication that *active* network parameters may have gaps in their epochs.
val newNetParams = setNetParams.toNetworkParameters(modifiedTime = Instant.now(), epoch = latestNetParams.epoch + 1)
logger.info("Enabling update to network parameters:\n$newNetParams\n$parametersUpdate")
require(!sameNetworkParameters(latestNetParams, newNetParams)) { "New network parameters are the same as the latest ones" }
networkMapStorage.saveNewParametersUpdate(newNetParams, parametersUpdate.description, parametersUpdate.updateDeadline)
logger.info("Update enabled")
println("Enabled update to network parameters:\n$newNetParams\n$parametersUpdate")
}
}
private fun sameNetworkParameters(params1: NetworkParameters, params2: NetworkParameters): Boolean {
return params1.copy(epoch = 1, modifiedTime = Instant.MAX) == params2.copy(epoch = 1, modifiedTime = Instant.MAX)
}
private fun handleFlagDay() {
val parametersUpdate = checkNotNull(networkMapStorage.getCurrentParametersUpdate()) {
"No network parameters updates are scheduled"
}
check(Instant.now() >= parametersUpdate.updateDeadline) {
"Update deadline of ${parametersUpdate.updateDeadline} hasn't passed yet"
}
val latestNetParamsEntity = networkMapStorage.getLatestNetworkParameters()
check(parametersUpdate.networkParameters.hash == networkMapStorage.getLatestNetworkParameters()?.hash) {
"The latest network parameters is not the scheduled one:\n${latestNetParamsEntity?.networkParameters}\n${parametersUpdate.toParametersUpdate()}"
}
val activeNetParams = networkMapStorage.getNetworkMaps().publicNetworkMap?.networkParameters
check(parametersUpdate.networkParameters.isSigned) {
"Parameters we are trying to switch to haven't been signed yet"
}
logger.info("""Flag day has occurred, however the new network parameters won't be active until the new network map is signed.
From: ${activeNetParams?.networkParameters}
To: ${parametersUpdate.networkParameters.networkParameters}""")
networkMapStorage.setParametersUpdateStatus(parametersUpdate, UpdateStatus.FLAG_DAY)
}
private fun handleCancelUpdate() {
val parametersUpdate = checkNotNull(networkMapStorage.getCurrentParametersUpdate()) {
"No network parameters updates are scheduled"
}
logger.info("""Cancelling parameters update: ${parametersUpdate.toParametersUpdate()}.
However, the network map will continue to advertise this update until the new one is signed.""")
networkMapStorage.setParametersUpdateStatus(parametersUpdate, UpdateStatus.CANCELLED)
println("Done with cancel update")
}
}

View File

@ -13,6 +13,7 @@ package com.r3.corda.networkmanage.doorman
import com.typesafe.config.ConfigFactory
import net.corda.core.internal.readObject
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo
import net.corda.core.node.NotaryInfo
import net.corda.nodeapi.internal.SignedNodeInfo
import java.nio.file.Path
@ -25,14 +26,15 @@ import java.time.Instant
*/
data class NotaryConfig(private val notaryNodeInfoFile: Path,
private val validating: Boolean) {
// TODO ENT-1608 - Check that the identity belongs to us
val nodeInfo by lazy { toNodeInfo() }
fun toNotaryInfo(): NotaryInfo {
val nodeInfo = notaryNodeInfoFile.readObject<SignedNodeInfo>().verified()
// It is always the last identity (in the list of identities) that corresponds to the notary identity.
// In case of a single notary, the list has only one element. In case of distributed notaries the list has
// two items and the second one corresponds to the notary identity.
return NotaryInfo(nodeInfo.legalIdentities.last(), validating)
}
private fun toNodeInfo(): NodeInfo = notaryNodeInfoFile.readObject<SignedNodeInfo>().verified()
}
data class ParametersUpdateConfig(val description: String, val updateDeadline: Instant) {

View File

@ -0,0 +1,122 @@
package com.r3.corda.networkmanage.doorman
import com.r3.corda.networkmanage.common.persistence.CertificateSigningRequestStorage
import com.r3.corda.networkmanage.common.persistence.NetworkMapStorage
import com.r3.corda.networkmanage.common.persistence.entity.UpdateStatus
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigParseOptions
import net.corda.core.internal.CertRole
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.config.parseAs
import net.corda.nodeapi.internal.crypto.x509Certificates
import java.nio.file.Path
import java.time.Instant
class ParametersUpdateHandler(val csrStorage: CertificateSigningRequestStorage, val networkMapStorage: NetworkMapStorage) {
companion object {
private val logger = contextLogger()
}
fun loadParametersFromFile(file: Path): NetworkParametersCmd.Set {
val netParamsConfig = ConfigFactory.parseFile(file.toFile(), ConfigParseOptions.defaults())
.parseAs<NetworkParametersConfig>()
checkNotaryCertificates(netParamsConfig.notaries.map { it.nodeInfo })
return NetworkParametersCmd.Set.fromConfig(netParamsConfig)
}
fun processNetworkParameters(networkParametersCmd: NetworkParametersCmd) {
when (networkParametersCmd) {
is NetworkParametersCmd.Set -> handleSetNetworkParameters(networkParametersCmd)
NetworkParametersCmd.FlagDay -> handleFlagDay()
NetworkParametersCmd.CancelUpdate -> handleCancelUpdate()
}
}
private fun checkNotaryCertificates(notaryNodeInfos: List<NodeInfo>) {
notaryNodeInfos.forEach { notaryInfo ->
val cert = notaryInfo.legalIdentitiesAndCerts.last().certPath.x509Certificates.find {
val certRole = CertRole.extract(it)
certRole == CertRole.SERVICE_IDENTITY || certRole == CertRole.NODE_CA
}
cert ?: throw IllegalArgumentException("The notary certificate path does not contain SERVICE_IDENTITY or NODE_CA role in it")
csrStorage.getValidCertificatePath(cert.publicKey)
?: throw IllegalArgumentException("Notary with node info: $notaryInfo is not registered with the doorman")
}
}
private fun handleSetNetworkParameters(setNetParams: NetworkParametersCmd.Set) {
logger.info("maxMessageSize is not currently wired in the nodes")
val activeNetParams = networkMapStorage.getNetworkMaps().publicNetworkMap?.networkParameters?.networkParameters
if (activeNetParams == null) {
require(setNetParams.parametersUpdate == null) {
"'parametersUpdate' specified in network parameters file but there are no network parameters to update"
}
val initialNetParams = setNetParams.toNetworkParameters(modifiedTime = Instant.now(), epoch = 1)
logger.info("Saving initial network parameters to be signed:\n$initialNetParams")
networkMapStorage.saveNetworkParameters(initialNetParams, null)
println("Saved initial network parameters to be signed:\n$initialNetParams")
} else {
val parametersUpdate = requireNotNull(setNetParams.parametersUpdate) {
"'parametersUpdate' not specified in network parameters file but there is already an active set of network parameters"
}
setNetParams.checkCompatibility(activeNetParams)
val latestNetParams = checkNotNull(networkMapStorage.getLatestNetworkParameters()?.networkParameters) {
"Something has gone wrong! We have an active set of network parameters ($activeNetParams) but apparently no latest network parameters!"
}
// It's not necessary that latestNetParams is the current active network parameters. It can be the network
// parameters from a previous update attempt which has't activated yet. We still take the epoch value for this
// new set from latestNetParams to make sure the advertised update attempts have incrementing epochs.
// This has the implication that *active* network parameters may have gaps in their epochs.
val newNetParams = setNetParams.toNetworkParameters(modifiedTime = Instant.now(), epoch = latestNetParams.epoch + 1)
logger.info("Enabling update to network parameters:\n$newNetParams\n$parametersUpdate")
require(!sameNetworkParameters(latestNetParams, newNetParams)) { "New network parameters are the same as the latest ones" }
networkMapStorage.saveNewParametersUpdate(newNetParams, parametersUpdate.description, parametersUpdate.updateDeadline)
logger.info("Update enabled")
println("Enabled update to network parameters:\n$newNetParams\n$parametersUpdate")
}
}
private fun sameNetworkParameters(params1: NetworkParameters, params2: NetworkParameters): Boolean {
return params1.copy(epoch = 1, modifiedTime = Instant.MAX) == params2.copy(epoch = 1, modifiedTime = Instant.MAX)
}
private fun handleFlagDay() {
val parametersUpdate = checkNotNull(networkMapStorage.getCurrentParametersUpdate()) {
"No network parameters updates are scheduled"
}
check(Instant.now() >= parametersUpdate.updateDeadline) {
"Update deadline of ${parametersUpdate.updateDeadline} hasn't passed yet"
}
val latestNetParamsEntity = networkMapStorage.getLatestNetworkParameters()
check(parametersUpdate.networkParameters.hash == networkMapStorage.getLatestNetworkParameters()?.hash) {
"The latest network parameters is not the scheduled one:\n${latestNetParamsEntity?.networkParameters}\n${parametersUpdate.toParametersUpdate()}"
}
val activeNetParams = networkMapStorage.getNetworkMaps().publicNetworkMap?.networkParameters
check(parametersUpdate.networkParameters.isSigned) {
"Parameters we are trying to switch to haven't been signed yet"
}
logger.info("""Flag day has occurred, however the new network parameters won't be active until the new network map is signed.
From: ${activeNetParams?.networkParameters}
To: ${parametersUpdate.networkParameters.networkParameters}""")
networkMapStorage.setParametersUpdateStatus(parametersUpdate, UpdateStatus.FLAG_DAY)
}
private fun handleCancelUpdate() {
val parametersUpdate = checkNotNull(networkMapStorage.getCurrentParametersUpdate()) {
"No network parameters updates are scheduled"
}
logger.info("""Cancelling parameters update: ${parametersUpdate.toParametersUpdate()}.
However, the network map will continue to advertise this update until the new one is signed.""")
networkMapStorage.setParametersUpdateStatus(parametersUpdate, UpdateStatus.CANCELLED)
println("Done with cancel update")
}
}

View File

@ -254,12 +254,12 @@ class PersistentNodeInfoStorageTest : TestBase() {
}
}
private fun createValidNodeInfo(organisation: String, storage: CertificateSigningRequestStorage): Pair<NodeInfo, PrivateKey> {
internal fun createValidNodeInfo(organisation: String, storage: CertificateSigningRequestStorage): Pair<NodeInfo, PrivateKey> {
val (nodeInfo, keys) = createValidNodeInfo(storage, CertRole.NODE_CA to organisation)
return Pair(nodeInfo, keys.single())
}
private fun createValidNodeInfo(storage: CertificateSigningRequestStorage, vararg identities: Pair<CertRole, String>): Pair<NodeInfo, List<PrivateKey>> {
internal fun createValidNodeInfo(storage: CertificateSigningRequestStorage, vararg identities: Pair<CertRole, String>): Pair<NodeInfo, List<PrivateKey>> {
val nodeInfoBuilder = TestNodeInfoBuilder()
val keys = identities.map { (certRole, name) ->
val (csr, nodeKeyPair) = createRequest(name, certRole = certRole)

View File

@ -41,7 +41,10 @@ class NotaryConfigTest {
val file = fs.getPath(UUID.randomUUID().toString())
signedNodeInfo.serialize().open().copyTo(file)
val notaryInfo = NotaryConfig(file, true).toNotaryInfo()
val notaryConfig = NotaryConfig(file, true)
val notaryInfo = notaryConfig.toNotaryInfo()
val nodeInfoFromFile = notaryConfig.nodeInfo
assertThat(nodeInfoFromFile).isEqualTo(nodeInfo)
assertThat(notaryInfo.identity).isEqualTo(nodeInfo.legalIdentities[0])
assertThat(notaryInfo.validating).isTrue()
}

View File

@ -0,0 +1,90 @@
package com.r3.corda.networkmanage.doorman
import com.nhaarman.mockito_kotlin.mock
import com.r3.corda.networkmanage.common.persistence.*
import com.typesafe.config.*
import net.corda.core.internal.*
import net.corda.core.serialization.serialize
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.internal.signWith
import net.corda.testing.node.MockServices
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.nio.file.Path
import java.util.*
class ParametersUpdateHandlerTest {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
@Rule
@JvmField
val tempFolder = TemporaryFolder()
private lateinit var persistence: CordaPersistence
private lateinit var csrStorage: CertificateSigningRequestStorage
private lateinit var netParamsUpdateHandler: ParametersUpdateHandler
@Before
fun init() {
persistence = configureDatabase(MockServices.makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
csrStorage = PersistentCertificateSigningRequestStorage(persistence)
netParamsUpdateHandler = ParametersUpdateHandler(csrStorage, mock())
}
@After
fun cleanUp() {
persistence.close()
}
@Test
fun `load parameters from file and check notaries registered`() {
// Create identities and put them into CertificateSigningStorage
val (nodeInfo1, keys1) = createValidNodeInfo(csrStorage, CertRole.NODE_CA to "Alice", CertRole.SERVICE_IDENTITY to "Alice Notary")
val (nodeInfo2, keys2) = createValidNodeInfo(csrStorage, CertRole.NODE_CA to "Bob Notary")
val signedNodeInfo1 = nodeInfo1.signWith(keys1)
val signedNodeInfo2 = nodeInfo2.signWith(keys2)
val notaryFile1 = tempFolder.root.toPath() / UUID.randomUUID().toString()
val notaryFile2 = tempFolder.root.toPath() / UUID.randomUUID().toString()
signedNodeInfo1.serialize().open().copyTo(notaryFile1)
signedNodeInfo2.serialize().open().copyTo(notaryFile2)
val configFile = tempFolder.root.toPath() / UUID.randomUUID().toString()
saveConfig(configFile, listOf(notaryFile1, notaryFile2))
val cmd = netParamsUpdateHandler.loadParametersFromFile(configFile)
assertThat(cmd.notaries.map { it.identity }).containsExactly(nodeInfo1.legalIdentities.last(), nodeInfo2.legalIdentities.last())
}
@Test
fun `notaries not registered`() {
// Create notary NodeInfo with SERVICE_IDENTITY role but don't put in CertificateSigningStorage
val (nodeInfo, keys) = createValidNodeInfo(mock(), CertRole.NODE_CA to "Alice", CertRole.SERVICE_IDENTITY to "Alice Notary")
val signedNodeInfo = nodeInfo.signWith(keys)
val notaryFile = tempFolder.root.toPath() / UUID.randomUUID().toString()
signedNodeInfo.serialize().open().copyTo(notaryFile)
val configFile = tempFolder.root.toPath() / UUID.randomUUID().toString()
saveConfig(configFile, listOf(notaryFile))
Assertions.assertThatThrownBy {netParamsUpdateHandler.loadParametersFromFile(configFile)}
.isInstanceOf(IllegalArgumentException::class.java)
.hasMessageContaining("is not registered with the doorman")
}
private fun saveConfig(configFile: Path, notaryFiles: List<Path>) {
val config = ConfigValueFactory.fromMap(
mapOf("minimumPlatformVersion" to 1,
"maxMessageSize" to 10485760,
"maxTransactionSize" to 10485760,
"notaries" to notaryFiles.map { mapOf("notaryNodeInfoFile" to it.toString(), "validating" to true) }
)
).toConfig()
val configString = config.root().render(ConfigRenderOptions.defaults())
configFile.writeText(configString)
}
}