mirror of
https://github.com/corda/corda.git
synced 2025-02-20 09:26:41 +00:00
CORDA-1733 X500Principal configuration parsing (#3580)
CORDA-1733 X500Principal configuration parsing Change the NodeConfiguration.tlsCertCrlIssuer type from String to X500Principal
This commit is contained in:
parent
5dd85e08bf
commit
4fb7f7d3d0
@ -22,6 +22,7 @@ import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.temporal.Temporal
|
||||
import java.util.*
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KType
|
||||
@ -128,6 +129,7 @@ private fun Config.getSingleValue(path: String, type: KType, onUnknownKeys: (Set
|
||||
Path::class -> Paths.get(getString(path))
|
||||
URL::class -> URL(getString(path))
|
||||
UUID::class -> UUID.fromString(getString(path))
|
||||
X500Principal::class -> X500Principal(getString(path))
|
||||
CordaX500Name::class -> {
|
||||
when (getValue(path).valueType()) {
|
||||
ConfigValueType.OBJECT -> getConfig(path).parseAs(onUnknownKeys)
|
||||
@ -173,6 +175,7 @@ private fun Config.getCollectionValue(path: String, type: KType, onUnknownKeys:
|
||||
NetworkHostAndPort::class -> getStringList(path).map(NetworkHostAndPort.Companion::parse)
|
||||
Path::class -> getStringList(path).map { Paths.get(it) }
|
||||
URL::class -> getStringList(path).map(::URL)
|
||||
X500Principal::class -> getStringList(path).map(::X500Principal)
|
||||
UUID::class -> getStringList(path).map { UUID.fromString(it) }
|
||||
CordaX500Name::class -> getStringList(path).map(CordaX500Name.Companion::parse)
|
||||
Properties::class -> getConfigList(path).map(Config::toProperties)
|
||||
@ -226,7 +229,7 @@ private fun Any.toConfigMap(): Map<String, Any> {
|
||||
val configValue = if (value is String || value is Boolean || value is Number) {
|
||||
// These types are supported by Config as use as is
|
||||
value
|
||||
} else if (value is Temporal || value is NetworkHostAndPort || value is CordaX500Name || value is Path || value is URL || value is UUID) {
|
||||
} else if (value is Temporal || value is NetworkHostAndPort || value is CordaX500Name || value is Path || value is URL || value is UUID || value is X500Principal) {
|
||||
// These types make sense to be represented as Strings and the exact inverse parsing function for use in parseAs
|
||||
value.toString()
|
||||
} else if (value is Enum<*>) {
|
||||
@ -261,6 +264,7 @@ private fun Iterable<*>.toConfigIterable(field: Field): Iterable<Any?> {
|
||||
NetworkHostAndPort::class.java -> map(Any?::toString)
|
||||
Path::class.java -> map(Any?::toString)
|
||||
URL::class.java -> map(Any?::toString)
|
||||
X500Principal::class.java -> map(Any?::toString)
|
||||
UUID::class.java -> map(Any?::toString)
|
||||
CordaX500Name::class.java -> map(Any?::toString)
|
||||
Properties::class.java -> map { ConfigFactory.parseMap(uncheckedCast(it)).root() }
|
||||
|
@ -14,6 +14,7 @@ import java.nio.file.Path
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
|
||||
class ConfigParsingTest {
|
||||
@ -84,6 +85,11 @@ class ConfigParsingTest {
|
||||
testPropertyType<URLData, URLListData, URL>(URL("http://localhost:1234"), URL("http://localhost:1235"), valuesToString = true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun X500Principal() {
|
||||
testPropertyType<X500PrincipalData, X500PrincipalListData, X500Principal>(X500Principal("C=US, L=New York, CN=Corda Root CA, OU=Corda, O=R3 HoldCo LLC"), X500Principal("O=Bank A,L=London,C=GB"), valuesToString = true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun UUID() {
|
||||
testPropertyType<UUIDData, UUIDListData, UUID>(UUID.randomUUID(), UUID.randomUUID(), valuesToString = true)
|
||||
@ -324,6 +330,8 @@ class ConfigParsingTest {
|
||||
data class PathListData(override val values: List<Path>) : ListData<Path>
|
||||
data class URLData(override val value: URL) : SingleData<URL>
|
||||
data class URLListData(override val values: List<URL>) : ListData<URL>
|
||||
data class X500PrincipalData(override val value: X500Principal) : SingleData<X500Principal>
|
||||
data class X500PrincipalListData(override val values: List<X500Principal>) : ListData<X500Principal>
|
||||
data class UUIDData(override val value: UUID) : SingleData<UUID>
|
||||
data class UUIDListData(override val values: List<UUID>) : ListData<UUID>
|
||||
data class CordaX500NameData(override val value: CordaX500Name) : SingleData<CordaX500Name>
|
||||
|
@ -16,12 +16,12 @@ import net.corda.nodeapi.internal.config.User
|
||||
import net.corda.nodeapi.internal.config.parseAs
|
||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||
import net.corda.tools.shell.SSHDConfiguration
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.slf4j.Logger
|
||||
import java.net.URL
|
||||
import java.nio.file.Path
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import javax.security.auth.x500.X500Principal
|
||||
|
||||
val Int.MB: Long get() = this * 1024L * 1024L
|
||||
|
||||
@ -63,7 +63,7 @@ interface NodeConfiguration : NodeSSLConfiguration {
|
||||
val drainingModePollPeriod: Duration get() = Duration.ofSeconds(5)
|
||||
val extraNetworkMapKeys: List<UUID>
|
||||
val tlsCertCrlDistPoint: URL?
|
||||
val tlsCertCrlIssuer: String?
|
||||
val tlsCertCrlIssuer: X500Principal?
|
||||
val effectiveH2Settings: NodeH2Settings?
|
||||
val flowMonitorPeriodMillis: Duration get() = DEFAULT_FLOW_MONITOR_PERIOD_MILLIS
|
||||
val flowMonitorSuspensionLoggingThresholdMillis: Duration get() = DEFAULT_FLOW_MONITOR_SUSPENSION_LOGGING_THRESHOLD_MILLIS
|
||||
@ -168,7 +168,7 @@ data class NodeConfigurationImpl(
|
||||
override val compatibilityZoneURL: URL? = null,
|
||||
override var networkServices: NetworkServicesConfig? = null,
|
||||
override val tlsCertCrlDistPoint: URL? = null,
|
||||
override val tlsCertCrlIssuer: String? = null,
|
||||
override val tlsCertCrlIssuer: X500Principal? = null,
|
||||
override val rpcUsers: List<User>,
|
||||
override val security: SecurityConfiguration? = null,
|
||||
override val verifierType: VerifierType,
|
||||
@ -237,11 +237,6 @@ data class NodeConfigurationImpl(
|
||||
if (tlsCertCrlDistPoint == null) {
|
||||
errors += "tlsCertCrlDistPoint needs to be specified when tlsCertCrlIssuer is not NULL"
|
||||
}
|
||||
try {
|
||||
X500Name(tlsCertCrlIssuer)
|
||||
} catch (e: Exception) {
|
||||
errors += "Error when parsing tlsCertCrlIssuer: ${e.message}"
|
||||
}
|
||||
}
|
||||
if (!crlCheckSoftFail && tlsCertCrlDistPoint == null) {
|
||||
errors += "tlsCertCrlDistPoint needs to be specified when crlCheckSoftFail is FALSE"
|
||||
|
@ -283,20 +283,20 @@ class NodeRegistrationHelper(private val config: NodeConfiguration, certService:
|
||||
}
|
||||
|
||||
override fun validateAndGetTlsCrlIssuerCert(): X509Certificate? {
|
||||
config.tlsCertCrlIssuer ?: return null
|
||||
val tlsCertCrlIssuerPrincipal = X500Principal(config.tlsCertCrlIssuer)
|
||||
if (principalMatchesCertificatePrincipal(tlsCertCrlIssuerPrincipal, rootCert)) {
|
||||
val tlsCertCrlIssuer = config.tlsCertCrlIssuer
|
||||
tlsCertCrlIssuer ?: return null
|
||||
if (principalMatchesCertificatePrincipal(tlsCertCrlIssuer, rootCert)) {
|
||||
return rootCert
|
||||
}
|
||||
return if (config.trustStoreFile.exists()) {
|
||||
findMatchingCertificate(tlsCertCrlIssuerPrincipal, config.loadTrustStore())
|
||||
findMatchingCertificate(tlsCertCrlIssuer, config.loadTrustStore())
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun isTlsCrlIssuerCertRequired(): Boolean {
|
||||
return !config.tlsCertCrlIssuer.isNullOrEmpty()
|
||||
return config.tlsCertCrlIssuer != null
|
||||
}
|
||||
|
||||
private fun findMatchingCertificate(principal: X500Principal, trustStore: X509KeyStore): X509Certificate? {
|
||||
|
@ -14,6 +14,7 @@ import org.junit.Test
|
||||
import java.net.URI
|
||||
import java.net.URL
|
||||
import java.nio.file.Paths
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@ -34,13 +35,6 @@ class NodeConfigurationImplTest {
|
||||
assertThat(configValidationResult.first()).contains("tlsCertCrlDistPoint needs to be specified when tlsCertCrlIssuer is not NULL")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `tlsCertCrlIssuer validation fails when misconfigured`() {
|
||||
val configValidationResult = configTlsCertCrlOptions(URL("http://test.com/crl"), "Corda Root CA").validate()
|
||||
assertTrue { configValidationResult.isNotEmpty() }
|
||||
assertThat(configValidationResult.first()).contains("Error when parsing tlsCertCrlIssuer:")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can't have tlsCertCrlDistPoint null when crlCheckSoftFail is false`() {
|
||||
val configValidationResult = configTlsCertCrlOptions(null, null, false).validate()
|
||||
@ -218,7 +212,7 @@ class NodeConfigurationImplTest {
|
||||
}
|
||||
|
||||
private fun configTlsCertCrlOptions(tlsCertCrlDistPoint: URL?, tlsCertCrlIssuer: String?, crlCheckSoftFail: Boolean = true): NodeConfiguration {
|
||||
return testConfiguration.copy(tlsCertCrlDistPoint = tlsCertCrlDistPoint, tlsCertCrlIssuer = tlsCertCrlIssuer, crlCheckSoftFail = crlCheckSoftFail)
|
||||
return testConfiguration.copy(tlsCertCrlDistPoint = tlsCertCrlDistPoint, tlsCertCrlIssuer = tlsCertCrlIssuer?.let { X500Principal(it) }, crlCheckSoftFail = crlCheckSoftFail)
|
||||
}
|
||||
|
||||
private val testConfiguration = testNodeConfiguration()
|
||||
|
Loading…
x
Reference in New Issue
Block a user