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:
Katarzyna Streich 2018-07-13 13:44:29 +01:00 committed by GitHub
parent 5dd85e08bf
commit 4fb7f7d3d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 23 additions and 22 deletions

View File

@ -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() }

View File

@ -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>

View File

@ -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"

View File

@ -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? {

View File

@ -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()