Legal name validation for X500Name (#983)

* * Legal name validation for X500Name while loading from config file.

* * Removed unintended changes.
This commit is contained in:
Patrick Kuo 2017-07-11 12:09:30 +01:00 committed by GitHub
parent d52b0e5db9
commit 7e8de79848
5 changed files with 15 additions and 8 deletions

View File

@ -2,6 +2,8 @@
package net.corda.core.utilities package net.corda.core.utilities
import net.corda.core.crypto.commonName
import org.bouncycastle.asn1.x500.X500Name
import java.lang.Character.UnicodeScript.* import java.lang.Character.UnicodeScript.*
import java.text.Normalizer import java.text.Normalizer
import java.util.regex.Pattern import java.util.regex.Pattern
@ -19,9 +21,13 @@ import javax.security.auth.x500.X500Principal
* *
* @throws IllegalArgumentException if the name does not meet the required rules. The message indicates why not. * @throws IllegalArgumentException if the name does not meet the required rules. The message indicates why not.
*/ */
@Throws(IllegalArgumentException::class)
fun validateLegalName(normalizedLegalName: String) { fun validateLegalName(normalizedLegalName: String) {
rules.forEach { it.validate(normalizedLegalName) } legalNameRules.forEach { it.validate(normalizedLegalName) }
}
// TODO: Implement X500 attribute validation once the specification has been finalised.
fun validateX500Name(x500Name: X500Name) {
validateLegalName(x500Name.commonName)
} }
val WHITESPACE = "\\s++".toRegex() val WHITESPACE = "\\s++".toRegex()
@ -35,7 +41,7 @@ fun normaliseLegalName(legalName: String): String {
return Normalizer.normalize(trimmedLegalName, Normalizer.Form.NFKC) return Normalizer.normalize(trimmedLegalName, Normalizer.Form.NFKC)
} }
private val rules: List<Rule<String>> = listOf( private val legalNameRules: List<Rule<String>> = listOf(
UnicodeNormalizationRule(), UnicodeNormalizationRule(),
CharacterRule(',', '=', '$', '"', '\'', '\\'), CharacterRule(',', '=', '$', '"', '\'', '\\'),
WordRule("node", "server"), WordRule("node", "server"),
@ -107,7 +113,7 @@ private class X500NameRule : Rule<String> {
private class MustHaveAtLeastTwoLettersRule : Rule<String> { private class MustHaveAtLeastTwoLettersRule : Rule<String> {
override fun validate(legalName: String) { override fun validate(legalName: String) {
// Try to exclude names like "/", "£", "X" etc. // Try to exclude names like "/", "£", "X" etc.
require(legalName.count { it.isLetter() } >= 3) { "Must have at least two letters" } require(legalName.count { it.isLetter() } >= 3) { "Illegal input legal name '$legalName'. Legal name must have at least two letters" }
} }
} }

View File

@ -3,6 +3,7 @@ package net.corda.nodeapi.config
import com.typesafe.config.Config import com.typesafe.config.Config
import com.typesafe.config.ConfigUtil import com.typesafe.config.ConfigUtil
import net.corda.core.noneOrSingle import net.corda.core.noneOrSingle
import net.corda.core.utilities.validateX500Name
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.parseNetworkHostAndPort import net.corda.core.utilities.parseNetworkHostAndPort
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
@ -72,7 +73,7 @@ private fun Config.getSingleValue(path: String, type: KType): Any? {
Path::class -> Paths.get(getString(path)) Path::class -> Paths.get(getString(path))
URL::class -> URL(getString(path)) URL::class -> URL(getString(path))
Properties::class -> getConfig(path).toProperties() Properties::class -> getConfig(path).toProperties()
X500Name::class -> X500Name(getString(path)) X500Name::class -> X500Name(getString(path)).apply(::validateX500Name)
else -> if (typeClass.java.isEnum) { else -> if (typeClass.java.isEnum) {
parseEnum(typeClass.java, getString(path)) parseEnum(typeClass.java, getString(path))
} else { } else {

View File

@ -112,7 +112,7 @@ class ConfigParsingTest {
@Test @Test
fun x500Name() { fun x500Name() {
testPropertyType<X500NameData, X500NameListData, X500Name>(getTestX509Name("Mock Node"), getTestX509Name("Mock Node 2"), valuesToString = true) testPropertyType<X500NameData, X500NameListData, X500Name>(getTestX509Name("Mock Party"), getTestX509Name("Mock Party 2"), valuesToString = true)
} }
@Test @Test

View File

@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger
class P2PMessagingTest : NodeBasedTest() { class P2PMessagingTest : NodeBasedTest() {
private companion object { private companion object {
val DISTRIBUTED_SERVICE_NAME = getTestX509Name("DistributedService") val DISTRIBUTED_SERVICE_NAME = getTestX509Name("DistributedService")
val SERVICE_2_NAME = getTestX509Name("Service Node 2") val SERVICE_2_NAME = getTestX509Name("Service 2")
} }
@Test @Test

View File

@ -30,7 +30,7 @@ class P2PSecurityTest : NodeBasedTest() {
@Test @Test
fun `incorrect legal name for the network map service config`() { fun `incorrect legal name for the network map service config`() {
val incorrectNetworkMapName = X509Utilities.getDevX509Name(random63BitValue().toString()) val incorrectNetworkMapName = X509Utilities.getDevX509Name("NetworkMap-${random63BitValue()}")
val node = startNode(BOB.name, configOverrides = mapOf( val node = startNode(BOB.name, configOverrides = mapOf(
"networkMapService" to mapOf( "networkMapService" to mapOf(
"address" to networkMapNode.configuration.p2pAddress.toString(), "address" to networkMapNode.configuration.p2pAddress.toString(),