mirror of
https://github.com/corda/corda.git
synced 2024-12-20 05:28:21 +00:00
CORDA-3452: Node: Configure the input of custom string in CSR (#5844)
* CORDA-3452: Node: Configure the input of custom string in CSR to be used by Identity Service * CORDA-3452: Remove unused import * CORDA-3452: Add test for networkServices configuration
This commit is contained in:
parent
ce774e459a
commit
73a0782f5d
@ -1693,7 +1693,7 @@
|
|||||||
<ID>MaxLineLength:ConfigSections.kt$DatabaseConfigSpec$private val initialiseAppSchema by enum(SchemaInitializationType::class).optional().withDefaultValue(DatabaseConfig.Defaults.initialiseAppSchema)</ID>
|
<ID>MaxLineLength:ConfigSections.kt$DatabaseConfigSpec$private val initialiseAppSchema by enum(SchemaInitializationType::class).optional().withDefaultValue(DatabaseConfig.Defaults.initialiseAppSchema)</ID>
|
||||||
<ID>MaxLineLength:ConfigSections.kt$DatabaseConfigSpec$private val transactionIsolationLevel by enum(TransactionIsolationLevel::class).optional().withDefaultValue(DatabaseConfig.Defaults.transactionIsolationLevel)</ID>
|
<ID>MaxLineLength:ConfigSections.kt$DatabaseConfigSpec$private val transactionIsolationLevel by enum(TransactionIsolationLevel::class).optional().withDefaultValue(DatabaseConfig.Defaults.transactionIsolationLevel)</ID>
|
||||||
<ID>MaxLineLength:ConfigSections.kt$DatabaseConfigSpec$return valid(DatabaseConfig(configuration[initialiseSchema], configuration[initialiseAppSchema], configuration[transactionIsolationLevel], configuration[exportHibernateJMXStatistics], configuration[mappedSchemaCacheSize]))</ID>
|
<ID>MaxLineLength:ConfigSections.kt$DatabaseConfigSpec$return valid(DatabaseConfig(configuration[initialiseSchema], configuration[initialiseAppSchema], configuration[transactionIsolationLevel], configuration[exportHibernateJMXStatistics], configuration[mappedSchemaCacheSize]))</ID>
|
||||||
<ID>MaxLineLength:ConfigSections.kt$NetworkServicesConfigSpec$return valid(NetworkServicesConfig(configuration[doormanURL], configuration[networkMapURL], configuration[pnm], configuration[inferred]))</ID>
|
<ID>MaxLineLength:ConfigSections.kt$NetworkServicesConfigSpec$return valid(NetworkServicesConfig(configuration[doormanURL], configuration[networkMapURL], configuration[pnm], configuration[inferred], configuration[csrToken]))</ID>
|
||||||
<ID>MaxLineLength:ConfigSections.kt$NodeRpcSettingsSpec$return valid(NodeRpcSettings(configuration[address], configuration[adminAddress], configuration[standAloneBroker], configuration[useSsl], configuration[ssl]))</ID>
|
<ID>MaxLineLength:ConfigSections.kt$NodeRpcSettingsSpec$return valid(NodeRpcSettings(configuration[address], configuration[adminAddress], configuration[standAloneBroker], configuration[useSsl], configuration[ssl]))</ID>
|
||||||
<ID>MaxLineLength:ConfigSections.kt$NotaryConfigSpec$return valid(NotaryConfig(configuration[validating], configuration[serviceLegalName], configuration[className], configuration[etaMessageThresholdSeconds], configuration[extraConfig], configuration[raft], configuration[bftSMaRt]))</ID>
|
<ID>MaxLineLength:ConfigSections.kt$NotaryConfigSpec$return valid(NotaryConfig(configuration[validating], configuration[serviceLegalName], configuration[className], configuration[etaMessageThresholdSeconds], configuration[extraConfig], configuration[raft], configuration[bftSMaRt]))</ID>
|
||||||
<ID>MaxLineLength:ConfigSections.kt$SSHDConfigurationSpec$override fun parseValid(configuration: Config): Valid<SSHDConfiguration></ID>
|
<ID>MaxLineLength:ConfigSections.kt$SSHDConfigurationSpec$override fun parseValid(configuration: Config): Valid<SSHDConfiguration></ID>
|
||||||
@ -3808,6 +3808,7 @@
|
|||||||
<ID>SpreadOperator:FxTransactionBuildTutorial.kt$ForeignExchangeFlow$(*ourOutputState.map { StateAndContract(it, Cash.PROGRAM_ID) }.toTypedArray())</ID>
|
<ID>SpreadOperator:FxTransactionBuildTutorial.kt$ForeignExchangeFlow$(*ourOutputState.map { StateAndContract(it, Cash.PROGRAM_ID) }.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:FxTransactionBuildTutorial.kt$ForeignExchangeFlow$(*theirInputStates.toTypedArray())</ID>
|
<ID>SpreadOperator:FxTransactionBuildTutorial.kt$ForeignExchangeFlow$(*theirInputStates.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:FxTransactionBuildTutorial.kt$ForeignExchangeFlow$(*theirOutputState.map { StateAndContract(it, Cash.PROGRAM_ID) }.toTypedArray())</ID>
|
<ID>SpreadOperator:FxTransactionBuildTutorial.kt$ForeignExchangeFlow$(*theirOutputState.map { StateAndContract(it, Cash.PROGRAM_ID) }.toTypedArray())</ID>
|
||||||
|
<ID>SpreadOperator:HTTPNetworkRegistrationService.kt$HTTPNetworkRegistrationService$(OpaqueBytes(request.encoded), "Platform-Version" to "${versionInfo.platformVersion}", "Client-Version" to versionInfo.releaseVersion, "Private-Network-Map" to (config.pnm?.toString() ?: ""), *(config.csrToken?.let { arrayOf(CENM_SUBMISSION_TOKEN to it) } ?: arrayOf()))</ID>
|
||||||
<ID>SpreadOperator:HibernateQueryCriteriaParser.kt$AbstractQueryCriteriaParser$(*leftPredicates.toTypedArray())</ID>
|
<ID>SpreadOperator:HibernateQueryCriteriaParser.kt$AbstractQueryCriteriaParser$(*leftPredicates.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:HibernateQueryCriteriaParser.kt$AbstractQueryCriteriaParser$(*leftPredicates.toTypedArray(), *rightPredicates.toTypedArray())</ID>
|
<ID>SpreadOperator:HibernateQueryCriteriaParser.kt$AbstractQueryCriteriaParser$(*leftPredicates.toTypedArray(), *rightPredicates.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:HibernateQueryCriteriaParser.kt$AbstractQueryCriteriaParser$(*rightPredicates.toTypedArray())</ID>
|
<ID>SpreadOperator:HibernateQueryCriteriaParser.kt$AbstractQueryCriteriaParser$(*rightPredicates.toTypedArray())</ID>
|
||||||
|
@ -513,6 +513,15 @@ networkServices
|
|||||||
|
|
||||||
*Default:* not defined
|
*Default:* not defined
|
||||||
|
|
||||||
|
csrToken
|
||||||
|
Optional token to provide alongside the certificate signing request (CSR) as part of the HTTP header during node registration.
|
||||||
|
The token can be used by certificate signing authority (or Identity Manager Service) to verify additional identity requirements.
|
||||||
|
The maximum token length is limited by the maximum HTTP header size, which is normally 8KB, assuming that a few other internal
|
||||||
|
attributes are also present in the header. Also, the token length itself may never exceed 8192, limited by the database structure.
|
||||||
|
Only US-ASCII characters are allowed.
|
||||||
|
|
||||||
|
*Default:* not defined
|
||||||
|
|
||||||
.. _corda_configuration_file_p2pAddress:
|
.. _corda_configuration_file_p2pAddress:
|
||||||
|
|
||||||
p2pAddress
|
p2pAddress
|
||||||
|
@ -175,12 +175,15 @@ data class NotaryConfig(
|
|||||||
* set explicitly ([inferred] == false) or weather they have been inferred via the compatibilityZoneURL parameter
|
* set explicitly ([inferred] == false) or weather they have been inferred via the compatibilityZoneURL parameter
|
||||||
* ([inferred] == true) where both the network map and doorman are running on the same endpoint. Only one,
|
* ([inferred] == true) where both the network map and doorman are running on the same endpoint. Only one,
|
||||||
* compatibilityZoneURL or networkServices, can be set at any one time.
|
* compatibilityZoneURL or networkServices, can be set at any one time.
|
||||||
|
* @property csrToken Optional token to provide alongside the certificate signing request (CSR) as part of the HTTP header during
|
||||||
|
* node registration.
|
||||||
*/
|
*/
|
||||||
data class NetworkServicesConfig(
|
data class NetworkServicesConfig(
|
||||||
val doormanURL: URL,
|
val doormanURL: URL,
|
||||||
val networkMapURL: URL,
|
val networkMapURL: URL,
|
||||||
val pnm: UUID? = null,
|
val pnm: UUID? = null,
|
||||||
val inferred: Boolean = false
|
val inferred: Boolean = false,
|
||||||
|
val csrToken: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,9 +149,10 @@ internal object NetworkServicesConfigSpec : Configuration.Specification<NetworkS
|
|||||||
private val networkMapURL by string().mapValid(::toURL)
|
private val networkMapURL by string().mapValid(::toURL)
|
||||||
private val pnm by string().mapValid(::toUUID).optional()
|
private val pnm by string().mapValid(::toUUID).optional()
|
||||||
private val inferred by boolean().optional().withDefaultValue(false)
|
private val inferred by boolean().optional().withDefaultValue(false)
|
||||||
|
private val csrToken by string(sensitive = true).optional()
|
||||||
|
|
||||||
override fun parseValid(configuration: Config): Valid<NetworkServicesConfig> {
|
override fun parseValid(configuration: Config): Valid<NetworkServicesConfig> {
|
||||||
return valid(NetworkServicesConfig(configuration[doormanURL], configuration[networkMapURL], configuration[pnm], configuration[inferred]))
|
return valid(NetworkServicesConfig(configuration[doormanURL], configuration[networkMapURL], configuration[pnm], configuration[inferred], configuration[csrToken]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +22,13 @@ import javax.naming.ServiceUnavailableException
|
|||||||
|
|
||||||
class HTTPNetworkRegistrationService(
|
class HTTPNetworkRegistrationService(
|
||||||
val config : NetworkServicesConfig,
|
val config : NetworkServicesConfig,
|
||||||
val versionInfo: VersionInfo
|
val versionInfo: VersionInfo,
|
||||||
|
private val registrationURL: URL = URL("${config.doormanURL}/certificate")
|
||||||
) : NetworkRegistrationService {
|
) : NetworkRegistrationService {
|
||||||
private val registrationURL = URL("${config.doormanURL}/certificate")
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TRANSIENT_ERROR_STATUS_CODES = setOf(HTTP_BAD_GATEWAY, HTTP_UNAVAILABLE, HTTP_GATEWAY_TIMEOUT)
|
private val TRANSIENT_ERROR_STATUS_CODES = setOf(HTTP_BAD_GATEWAY, HTTP_UNAVAILABLE, HTTP_GATEWAY_TIMEOUT)
|
||||||
|
private const val CENM_SUBMISSION_TOKEN = "X-CENM-Submission-Token"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CertificateRequestException::class)
|
@Throws(CertificateRequestException::class)
|
||||||
@ -59,7 +60,8 @@ class HTTPNetworkRegistrationService(
|
|||||||
return String(registrationURL.post(OpaqueBytes(request.encoded),
|
return String(registrationURL.post(OpaqueBytes(request.encoded),
|
||||||
"Platform-Version" to "${versionInfo.platformVersion}",
|
"Platform-Version" to "${versionInfo.platformVersion}",
|
||||||
"Client-Version" to versionInfo.releaseVersion,
|
"Client-Version" to versionInfo.releaseVersion,
|
||||||
"Private-Network-Map" to (config.pnm?.toString() ?: "")))
|
"Private-Network-Map" to (config.pnm?.toString() ?: ""),
|
||||||
|
*(config.csrToken?.let { arrayOf(CENM_SUBMISSION_TOKEN to it) } ?: arrayOf())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +263,18 @@ class NodeConfigurationImplTest {
|
|||||||
assertEquals(JmxReporterType.JOLOKIA.toString(), nodeConfig.jmxReporterType.toString())
|
assertEquals(JmxReporterType.JOLOKIA.toString(), nodeConfig.jmxReporterType.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network services`() {
|
||||||
|
val rawConfig = getConfig("test-config-with-networkservices.conf")
|
||||||
|
val nodeConfig = rawConfig.parseAsNodeConfiguration().value()
|
||||||
|
nodeConfig.networkServices!!.apply {
|
||||||
|
assertEquals("https://registration.example.com", doormanURL.toString())
|
||||||
|
assertEquals("https://cz.example.com", networkMapURL.toString())
|
||||||
|
assertEquals("3c23d1a1-aa63-4beb-af9f-c8579dd5f89c", pnm.toString())
|
||||||
|
assertEquals("my-TOKEN", csrToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun configDebugOptions(devMode: Boolean, devModeOptions: DevModeOptions?): NodeConfigurationImpl {
|
private fun configDebugOptions(devMode: Boolean, devModeOptions: DevModeOptions?): NodeConfigurationImpl {
|
||||||
return testConfiguration.copy(devMode = devMode, devModeOptions = devModeOptions)
|
return testConfiguration.copy(devMode = devMode, devModeOptions = devModeOptions)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package net.corda.node.utilities.registration
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.anyOrNull
|
||||||
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
|
import net.corda.node.VersionInfo
|
||||||
|
import net.corda.node.services.config.NetworkServicesConfig
|
||||||
|
import net.corda.testing.internal.rigorousMock
|
||||||
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
|
import org.junit.Test
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class HTTPNetworkRegistrationServiceTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `post request properties`() {
|
||||||
|
val versionInfo = VersionInfo.UNKNOWN
|
||||||
|
val pnm = UUID.randomUUID();
|
||||||
|
val config = rigorousMock<NetworkServicesConfig>().also {
|
||||||
|
doReturn(pnm).whenever(it).pnm
|
||||||
|
doReturn(null).whenever(it).csrToken
|
||||||
|
}
|
||||||
|
var header = submitDummyRequest(versionInfo, config).requestProperties
|
||||||
|
assertEquals(4, header.size)
|
||||||
|
assertEquals(listOf(pnm.toString()), header["Private-Network-Map"])
|
||||||
|
assertEquals(listOf(versionInfo.platformVersion.toString()), header["Platform-Version"])
|
||||||
|
assertEquals(listOf(versionInfo.releaseVersion), header["Client-Version"])
|
||||||
|
assertEquals(listOf("application/octet-stream"), header["Content-Type"])
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `post request properties with CSR token`() {
|
||||||
|
val versionInfo = VersionInfo.UNKNOWN
|
||||||
|
val config = rigorousMock<NetworkServicesConfig>().also {
|
||||||
|
doReturn(null).whenever(it).pnm
|
||||||
|
doReturn("My-TOKEN").whenever(it).csrToken
|
||||||
|
}
|
||||||
|
var header = submitDummyRequest(versionInfo, config).requestProperties
|
||||||
|
assertEquals(5, header.size)
|
||||||
|
assertEquals(listOf(""), header["Private-Network-Map"])
|
||||||
|
assertEquals(listOf(versionInfo.platformVersion.toString()), header["Platform-Version"])
|
||||||
|
assertEquals(listOf(versionInfo.releaseVersion), header["Client-Version"])
|
||||||
|
assertEquals(listOf("application/octet-stream"), header["Content-Type"])
|
||||||
|
assertEquals(listOf("My-TOKEN"), header["X-CENM-Submission-Token"])
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun submitDummyRequest(versionInfo: VersionInfo, config: NetworkServicesConfig) : HttpURLConnection {
|
||||||
|
val request = rigorousMock<PKCS10CertificationRequest>().also {
|
||||||
|
doReturn("dummy".toByteArray()).whenever(it).encoded
|
||||||
|
}
|
||||||
|
val inputStream = rigorousMock<InputStream>().also {
|
||||||
|
doReturn(-1).whenever(it).read()
|
||||||
|
}
|
||||||
|
val connection = rigorousMock<HttpURLConnection>().also {
|
||||||
|
doReturn(inputStream).whenever(it).inputStream
|
||||||
|
doReturn(mock<OutputStream>()).whenever(it).outputStream
|
||||||
|
doReturn(HttpURLConnection.HTTP_OK).whenever(it).responseCode
|
||||||
|
}
|
||||||
|
val url = rigorousMock<URL>().also {
|
||||||
|
doReturn(connection).whenever(it).openConnection()
|
||||||
|
doReturn(connection).whenever(it).openConnection(anyOrNull())
|
||||||
|
}
|
||||||
|
val service = HTTPNetworkRegistrationService(config, versionInfo, url)
|
||||||
|
service.submitRequest(request)
|
||||||
|
return connection
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
myLegalName = "O=Bank A,L=London,C=GB"
|
||||||
|
p2pAddress = "my-corda-node:10002"
|
||||||
|
rpcSettings {
|
||||||
|
address = "my-corda-node:10003"
|
||||||
|
adminAddress = "my-corda-node:10004"
|
||||||
|
}
|
||||||
|
devMode = false
|
||||||
|
networkServices {
|
||||||
|
doormanURL = "https://registration.example.com"
|
||||||
|
networkMapURL = "https://cz.example.com"
|
||||||
|
pnm = "3c23d1a1-aa63-4beb-af9f-c8579dd5f89c"
|
||||||
|
csrToken = "my-TOKEN"
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user