mirror of
https://github.com/corda/corda.git
synced 2025-03-03 12:57:29 +00:00
Merge OS commit 'ab80df342ab8a7ede0539daaee9fcecd02f6aeeb' into enterprise
This commit is contained in:
commit
e5e98f3540
@ -94,7 +94,8 @@ class AMQPListenerTest {
|
|||||||
PEER_USER,
|
PEER_USER,
|
||||||
clientKeyStore,
|
clientKeyStore,
|
||||||
clientConfig.keyStorePassword,
|
clientConfig.keyStorePassword,
|
||||||
clientTrustStore)
|
clientTrustStore,
|
||||||
|
true)
|
||||||
|
|
||||||
amqpClient.start()
|
amqpClient.start()
|
||||||
// Should see events to show we got a valid connection
|
// Should see events to show we got a valid connection
|
||||||
@ -163,7 +164,8 @@ class AMQPListenerTest {
|
|||||||
PEER_USER,
|
PEER_USER,
|
||||||
clientKeyStore.internal,
|
clientKeyStore.internal,
|
||||||
"password",
|
"password",
|
||||||
clientTrustStore.internal)
|
clientTrustStore.internal,
|
||||||
|
true)
|
||||||
amqpClient.start()
|
amqpClient.start()
|
||||||
val connectionEvent = connectionFollower.next()
|
val connectionEvent = connectionFollower.next()
|
||||||
assertEquals(false, connectionEvent.connected)
|
assertEquals(false, connectionEvent.connected)
|
||||||
|
@ -29,8 +29,9 @@ data class BridgeSSLConfigurationImpl(override val keyStorePassword: String,
|
|||||||
override val trustStorePassword: String,
|
override val trustStorePassword: String,
|
||||||
override val certificatesDirectory: Path = Paths.get("certificates"),
|
override val certificatesDirectory: Path = Paths.get("certificates"),
|
||||||
override val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
|
override val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
|
||||||
override val trustStoreFile: Path = certificatesDirectory / "truststore.jks") : BridgeSSLConfiguration {
|
override val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
|
||||||
constructor(config: NodeSSLConfiguration) : this(config.keyStorePassword, config.trustStorePassword, config.certificatesDirectory, config.sslKeystore, config.trustStoreFile)
|
override val crlCheckSoftFail: Boolean) : BridgeSSLConfiguration {
|
||||||
|
constructor(config: NodeSSLConfiguration) : this(config.keyStorePassword, config.trustStorePassword, config.certificatesDirectory, config.sslKeystore, config.trustStoreFile, config.crlCheckSoftFail)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class BridgeOutboundConfigurationImpl(override val artemisBrokerAddress: NetworkHostAndPort,
|
data class BridgeOutboundConfigurationImpl(override val artemisBrokerAddress: NetworkHostAndPort,
|
||||||
@ -57,6 +58,7 @@ data class BridgeConfigurationImpl(
|
|||||||
override val certificatesDirectory: Path = baseDirectory / "certificates",
|
override val certificatesDirectory: Path = baseDirectory / "certificates",
|
||||||
override val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
|
override val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
|
||||||
override val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
|
override val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
|
||||||
|
override val crlCheckSoftFail: Boolean,
|
||||||
override val keyStorePassword: String,
|
override val keyStorePassword: String,
|
||||||
override val trustStorePassword: String,
|
override val trustStorePassword: String,
|
||||||
override val bridgeMode: BridgeMode,
|
override val bridgeMode: BridgeMode,
|
||||||
|
@ -60,7 +60,7 @@ class BridgeAMQPListenerServiceImpl(val conf: BridgeConfiguration,
|
|||||||
val keyStore = loadKeyStoreAndWipeKeys(keyStoreBytes, keyStorePassword)
|
val keyStore = loadKeyStoreAndWipeKeys(keyStoreBytes, keyStorePassword)
|
||||||
val trustStore = loadKeyStoreAndWipeKeys(trustStoreBytes, trustStorePassword)
|
val trustStore = loadKeyStoreAndWipeKeys(trustStoreBytes, trustStorePassword)
|
||||||
val bindAddress = conf.inboundConfig!!.listeningAddress
|
val bindAddress = conf.inboundConfig!!.listeningAddress
|
||||||
val server = AMQPServer(bindAddress.host, bindAddress.port, PEER_USER, PEER_USER, keyStore, keyStorePrivateKeyPassword, trustStore, conf.enableAMQPPacketTrace)
|
val server = AMQPServer(bindAddress.host, bindAddress.port, PEER_USER, PEER_USER, keyStore, keyStorePrivateKeyPassword, trustStore, conf.crlCheckSoftFail, conf.enableAMQPPacketTrace)
|
||||||
onConnectSubscription = server.onConnection.subscribe(_onConnection)
|
onConnectSubscription = server.onConnection.subscribe(_onConnection)
|
||||||
onConnectAuditSubscription = server.onConnection.subscribe {
|
onConnectAuditSubscription = server.onConnection.subscribe {
|
||||||
if (it.connected) {
|
if (it.connected) {
|
||||||
|
@ -82,7 +82,7 @@ class FloatControlListenerService(val conf: BridgeConfiguration,
|
|||||||
|
|
||||||
private fun startControlListener() {
|
private fun startControlListener() {
|
||||||
lock.withLock {
|
lock.withLock {
|
||||||
val controlServer = AMQPServer(floatControlAddress.host, floatControlAddress.port, null, null, keyStore, keyStorePrivateKeyPassword, trustStore, conf.enableAMQPPacketTrace)
|
val controlServer = AMQPServer(floatControlAddress.host, floatControlAddress.port, null, null, keyStore, keyStorePrivateKeyPassword, trustStore, conf.crlCheckSoftFail, conf.enableAMQPPacketTrace)
|
||||||
connectSubscriber = controlServer.onConnection.subscribe { onConnectToControl(it) }
|
connectSubscriber = controlServer.onConnection.subscribe { onConnectToControl(it) }
|
||||||
receiveSubscriber = controlServer.onReceive.subscribe { onControlMessage(it) }
|
receiveSubscriber = controlServer.onReceive.subscribe { onControlMessage(it) }
|
||||||
amqpControlServer = controlServer
|
amqpControlServer = controlServer
|
||||||
|
@ -72,7 +72,7 @@ class TunnelingBridgeReceiverService(val conf: BridgeConfiguration,
|
|||||||
statusSubscriber = statusFollower.activeChange.subscribe {
|
statusSubscriber = statusFollower.activeChange.subscribe {
|
||||||
if (it) {
|
if (it) {
|
||||||
val floatAddresses = conf.floatInnerConfig!!.floatAddresses
|
val floatAddresses = conf.floatInnerConfig!!.floatAddresses
|
||||||
val controlClient = AMQPClient(floatAddresses, setOf(expectedCertificateSubject), null, null, controlLinkKeyStore, controLinkKeyStorePrivateKeyPassword, controlLinkTrustStore, conf.enableAMQPPacketTrace)
|
val controlClient = AMQPClient(floatAddresses, setOf(expectedCertificateSubject), null, null, controlLinkKeyStore, controLinkKeyStorePrivateKeyPassword, controlLinkTrustStore, conf.crlCheckSoftFail, conf.enableAMQPPacketTrace)
|
||||||
connectSubscriber = controlClient.onConnection.subscribe { onConnectToControl(it) }
|
connectSubscriber = controlClient.onConnection.subscribe { onConnectToControl(it) }
|
||||||
receiveSubscriber = controlClient.onReceive.subscribe { onFloatMessage(it) }
|
receiveSubscriber = controlClient.onReceive.subscribe { onFloatMessage(it) }
|
||||||
amqpControlClient = controlClient
|
amqpControlClient = controlClient
|
||||||
|
@ -11,4 +11,5 @@ keyStorePassword = "cordacadevpass"
|
|||||||
trustStorePassword = "trustpass"
|
trustStorePassword = "trustpass"
|
||||||
enableAMQPPacketTrace = false
|
enableAMQPPacketTrace = false
|
||||||
artemisReconnectionInterval = 5000
|
artemisReconnectionInterval = 5000
|
||||||
politeShutdownPeriod = 1000
|
politeShutdownPeriod = 1000
|
||||||
|
crlCheckSoftFail = true
|
@ -15,4 +15,4 @@ outboundConfig : {
|
|||||||
inboundConfig : {
|
inboundConfig : {
|
||||||
listeningAddress = "0.0.0.0:10005"
|
listeningAddress = "0.0.0.0:10005"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -16,4 +16,4 @@ floatInnerConfig : {
|
|||||||
floatAddresses = [ "localhost:13005" ]
|
floatAddresses = [ "localhost:13005" ]
|
||||||
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -15,4 +15,4 @@ floatOuterConfig : {
|
|||||||
floatAddress = "localhost:13005"
|
floatAddress = "localhost:13005"
|
||||||
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -16,4 +16,4 @@ outboundConfig : {
|
|||||||
inboundConfig : {
|
inboundConfig : {
|
||||||
listeningAddress = "0.0.0.0:10005"
|
listeningAddress = "0.0.0.0:10005"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -15,4 +15,4 @@ floatOuterConfig : {
|
|||||||
floatAddress = "localhost:12005"
|
floatAddress = "localhost:12005"
|
||||||
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -15,6 +15,7 @@ outboundConfig : {
|
|||||||
trustStorePassword = "outboundtrustpassword"
|
trustStorePassword = "outboundtrustpassword"
|
||||||
sslKeystore = "outboundcerts/outboundkeys.jks"
|
sslKeystore = "outboundcerts/outboundkeys.jks"
|
||||||
trustStoreFile = "outboundcerts/outboundtrust.jks"
|
trustStoreFile = "outboundcerts/outboundtrust.jks"
|
||||||
|
crlCheckSoftFail = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
floatInnerConfig : {
|
floatInnerConfig : {
|
||||||
@ -25,6 +26,7 @@ floatInnerConfig : {
|
|||||||
trustStorePassword = "tunneltrustpassword"
|
trustStorePassword = "tunneltrustpassword"
|
||||||
sslKeystore = "tunnelcerts/tunnelkeys.jks"
|
sslKeystore = "tunnelcerts/tunnelkeys.jks"
|
||||||
trustStoreFile = "tunnelcerts/tunneltrust.jks"
|
trustStoreFile = "tunnelcerts/tunneltrust.jks"
|
||||||
|
crlCheckSoftFail = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -15,6 +15,7 @@ inboundConfig : {
|
|||||||
trustStorePassword = "inboundtrustpassword"
|
trustStorePassword = "inboundtrustpassword"
|
||||||
sslKeystore = "inboundcerts/inboundkeys.jks"
|
sslKeystore = "inboundcerts/inboundkeys.jks"
|
||||||
trustStoreFile = "inboundcerts/inboundtrust.jks"
|
trustStoreFile = "inboundcerts/inboundtrust.jks"
|
||||||
|
crlCheckSoftFail = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
floatOuterConfig : {
|
floatOuterConfig : {
|
||||||
@ -25,6 +26,7 @@ floatOuterConfig : {
|
|||||||
trustStorePassword = "tunneltrustpassword"
|
trustStorePassword = "tunneltrustpassword"
|
||||||
sslKeystore = "tunnelcerts/tunnelkeys.jks"
|
sslKeystore = "tunnelcerts/tunnelkeys.jks"
|
||||||
trustStoreFile = "tunnelcerts/tunneltrust.jks"
|
trustStoreFile = "tunnelcerts/tunneltrust.jks"
|
||||||
|
crlCheckSoftFail = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -14,4 +14,4 @@ outboundConfig : {
|
|||||||
inboundConfig : {
|
inboundConfig : {
|
||||||
listeningAddress = "0.0.0.0:10005"
|
listeningAddress = "0.0.0.0:10005"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -15,4 +15,4 @@ floatInnerConfig : {
|
|||||||
floatAddresses = [ "localhost:12005" ]
|
floatAddresses = [ "localhost:12005" ]
|
||||||
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -15,4 +15,4 @@ floatOuterConfig : {
|
|||||||
floatAddress = "localhost:12005"
|
floatAddress = "localhost:12005"
|
||||||
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -21,3 +21,4 @@ inboundConfig : {
|
|||||||
listeningAddress = "0.0.0.0:10005"
|
listeningAddress = "0.0.0.0:10005"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
||||||
|
crlCheckSoftFail = true
|
@ -21,3 +21,4 @@ inboundConfig : {
|
|||||||
listeningAddress = "0.0.0.0:10005"
|
listeningAddress = "0.0.0.0:10005"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
||||||
|
crlCheckSoftFail = true
|
@ -21,3 +21,4 @@ inboundConfig : {
|
|||||||
listeningAddress = "0.0.0.0:10005"
|
listeningAddress = "0.0.0.0:10005"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
||||||
|
crlCheckSoftFail = true
|
@ -20,4 +20,4 @@ outboundConfig : {
|
|||||||
inboundConfig : {
|
inboundConfig : {
|
||||||
listeningAddress = "0.0.0.0:10005"
|
listeningAddress = "0.0.0.0:10005"
|
||||||
}
|
}
|
||||||
networkParametersPath = network-parameters
|
networkParametersPath = network-parameters
|
@ -360,13 +360,14 @@ fun ExecutorService.join() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CertPath.validate(trustAnchor: TrustAnchor): PKIXCertPathValidatorResult {
|
// TODO: Currently the certificate revocation status is not handled here. Nowhere in the code the second parameter is used. Consider adding the support in the future.
|
||||||
val parameters = PKIXParameters(setOf(trustAnchor)).apply { isRevocationEnabled = false }
|
fun CertPath.validate(trustAnchor: TrustAnchor, checkRevocation: Boolean = false): PKIXCertPathValidatorResult {
|
||||||
|
val parameters = PKIXParameters(setOf(trustAnchor)).apply { isRevocationEnabled = checkRevocation }
|
||||||
try {
|
try {
|
||||||
return CertPathValidator.getInstance("PKIX").validate(this, parameters) as PKIXCertPathValidatorResult
|
return CertPathValidator.getInstance("PKIX").validate(this, parameters) as PKIXCertPathValidatorResult
|
||||||
} catch (e: CertPathValidatorException) {
|
} catch (e: CertPathValidatorException) {
|
||||||
throw CertPathValidatorException(
|
throw CertPathValidatorException(
|
||||||
"""Cert path failed to validate against trust anchor.
|
"""Cert path failed to validate.
|
||||||
Reason: ${e.reason}
|
Reason: ${e.reason}
|
||||||
Offending cert index: ${e.index}
|
Offending cert index: ${e.index}
|
||||||
Cert path: $this
|
Cert path: $this
|
||||||
|
@ -67,6 +67,11 @@ absolute path to the node's base directory.
|
|||||||
|
|
||||||
.. note:: Longer term these keys will be managed in secure hardware devices.
|
.. note:: Longer term these keys will be managed in secure hardware devices.
|
||||||
|
|
||||||
|
:crlCheckSoftFail: This is a boolean flag that when enabled (i.e. `true` value is set) the certificate revocation list (CRL) checking will use the soft fail mode.
|
||||||
|
The soft fail mode allows the revocation check to succeed if the revocation status cannot be determined because of a network error.
|
||||||
|
If this parameter is set to `false` the rigorous CRL checking takes place, meaning that each certificate in the
|
||||||
|
certificate path being checked needs to have the CRL distribution point extension set and pointing to a URL serving a valid CRL.
|
||||||
|
|
||||||
.. _database_properties_ref:
|
.. _database_properties_ref:
|
||||||
|
|
||||||
:database: This section is used to configure JDBC and Hibernate related properties:
|
:database: This section is used to configure JDBC and Hibernate related properties:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
myLegalName : "O=Bank A,L=London,C=GB"
|
myLegalName : "O=Bank A,L=London,C=GB"
|
||||||
keyStorePassword : "cordacadevpass"
|
keyStorePassword : "cordacadevpass"
|
||||||
trustStorePassword : "trustpass"
|
trustStorePassword : "trustpass"
|
||||||
|
crlCheckSoftFail: true
|
||||||
dataSourceProperties : {
|
dataSourceProperties : {
|
||||||
dataSourceClassName : org.h2.jdbcx.JdbcDataSource
|
dataSourceClassName : org.h2.jdbcx.JdbcDataSource
|
||||||
dataSource.url : "jdbc:h2:file:"${baseDirectory}"/persistence"
|
dataSource.url : "jdbc:h2:file:"${baseDirectory}"/persistence"
|
||||||
|
@ -47,6 +47,7 @@ fun RegistrationOption.runRegistration() {
|
|||||||
val parent = configFile.parent
|
val parent = configFile.parent
|
||||||
override val certificatesDirectory: Path = if (parent != null) parent / "certificates" else Paths.get("certificates")
|
override val certificatesDirectory: Path = if (parent != null) parent / "certificates" else Paths.get("certificates")
|
||||||
override val nodeKeystore: Path get() = config.keystorePath ?: certificatesDirectory/"notaryidentitykeystore.jks"
|
override val nodeKeystore: Path get() = config.keystorePath ?: certificatesDirectory/"notaryidentitykeystore.jks"
|
||||||
|
override val crlCheckSoftFail: Boolean = config.crlCheckSoftFail
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkRegistrationHelper(sslConfig,
|
NetworkRegistrationHelper(sslConfig,
|
||||||
@ -66,4 +67,5 @@ data class NotaryRegistrationConfig(val legalName: CordaX500Name,
|
|||||||
val keyStorePassword: String?,
|
val keyStorePassword: String?,
|
||||||
val networkRootTrustStorePassword: String?,
|
val networkRootTrustStorePassword: String?,
|
||||||
val trustStorePassword: String?,
|
val trustStorePassword: String?,
|
||||||
val keystorePath: Path?)
|
val keystorePath: Path?,
|
||||||
|
val crlCheckSoftFail: Boolean)
|
||||||
|
@ -13,9 +13,9 @@ package com.r3.corda.networkmanage.registration
|
|||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigParseOptions
|
import com.typesafe.config.ConfigParseOptions
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.CertRole
|
|
||||||
import net.corda.nodeapi.internal.config.parseAs
|
import net.corda.nodeapi.internal.config.parseAs
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ keystorePath = "notaryidentitykeystore.jks"
|
|||||||
networkRootTrustStorePassword = "password"
|
networkRootTrustStorePassword = "password"
|
||||||
keyStorePassword = "password"
|
keyStorePassword = "password"
|
||||||
trustStorePassword = "password"
|
trustStorePassword = "password"
|
||||||
|
crlCheckSoftFail = true
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
val config = ConfigFactory.parseString(testConfig, ConfigParseOptions.defaults().setAllowMissing(false))
|
val config = ConfigFactory.parseString(testConfig, ConfigParseOptions.defaults().setAllowMissing(false))
|
||||||
@ -49,5 +50,6 @@ trustStorePassword = "password"
|
|||||||
assertEquals(Paths.get("networkRootTrustStore.jks"), config.networkRootTrustStorePath)
|
assertEquals(Paths.get("networkRootTrustStore.jks"), config.networkRootTrustStorePath)
|
||||||
assertEquals("password", config.networkRootTrustStorePassword)
|
assertEquals("password", config.networkRootTrustStorePassword)
|
||||||
assertEquals(Paths.get("notaryidentitykeystore.jks"), config.keystorePath)
|
assertEquals(Paths.get("notaryidentitykeystore.jks"), config.keystorePath)
|
||||||
|
assertTrue(config.crlCheckSoftFail)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -45,6 +45,7 @@ object DevIdentityGenerator {
|
|||||||
override val baseDirectory = nodeDir
|
override val baseDirectory = nodeDir
|
||||||
override val keyStorePassword: String = "cordacadevpass"
|
override val keyStorePassword: String = "cordacadevpass"
|
||||||
override val trustStorePassword get() = throw NotImplementedError("Not expected to be called")
|
override val trustStorePassword get() = throw NotImplementedError("Not expected to be called")
|
||||||
|
override val crlCheckSoftFail: Boolean = true
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeSslConfig.certificatesDirectory.createDirectories()
|
nodeSslConfig.certificatesDirectory.createDirectories()
|
||||||
|
@ -57,6 +57,7 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val socksProxyConf
|
|||||||
private val keyStorePrivateKeyPassword: String = config.keyStorePassword
|
private val keyStorePrivateKeyPassword: String = config.keyStorePassword
|
||||||
private val trustStore = config.loadTrustStore().internal
|
private val trustStore = config.loadTrustStore().internal
|
||||||
private var artemis: ArtemisSessionProvider? = null
|
private var artemis: ArtemisSessionProvider? = null
|
||||||
|
private val crlCheckSoftFail: Boolean = config.crlCheckSoftFail
|
||||||
|
|
||||||
constructor(config: NodeSSLConfiguration, p2pAddress: NetworkHostAndPort, maxMessageSize: Int, socksProxyConfig: SocksProxyConfig? = null) : this(config, socksProxyConfig, { ArtemisMessagingClient(config, p2pAddress, maxMessageSize) })
|
constructor(config: NodeSSLConfiguration, p2pAddress: NetworkHostAndPort, maxMessageSize: Int, socksProxyConfig: SocksProxyConfig? = null) : this(config, socksProxyConfig, { ArtemisMessagingClient(config, p2pAddress, maxMessageSize) })
|
||||||
|
|
||||||
@ -78,6 +79,7 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val socksProxyConf
|
|||||||
keyStore: KeyStore,
|
keyStore: KeyStore,
|
||||||
keyStorePrivateKeyPassword: String,
|
keyStorePrivateKeyPassword: String,
|
||||||
trustStore: KeyStore,
|
trustStore: KeyStore,
|
||||||
|
crlCheckSoftFail: Boolean,
|
||||||
sharedEventGroup: EventLoopGroup,
|
sharedEventGroup: EventLoopGroup,
|
||||||
socksProxyConfig: SocksProxyConfig?,
|
socksProxyConfig: SocksProxyConfig?,
|
||||||
private val artemis: ArtemisSessionProvider) {
|
private val artemis: ArtemisSessionProvider) {
|
||||||
@ -87,7 +89,7 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val socksProxyConf
|
|||||||
|
|
||||||
private val log = LoggerFactory.getLogger("$bridgeName:${legalNames.first()}")
|
private val log = LoggerFactory.getLogger("$bridgeName:${legalNames.first()}")
|
||||||
|
|
||||||
val amqpClient = AMQPClient(listOf(target), legalNames, PEER_USER, PEER_USER, keyStore, keyStorePrivateKeyPassword, trustStore, sharedThreadPool = sharedEventGroup, socksProxyConfig = socksProxyConfig)
|
val amqpClient = AMQPClient(listOf(target), legalNames, PEER_USER, PEER_USER, keyStore, keyStorePrivateKeyPassword, trustStore, crlCheckSoftFail, sharedThreadPool = sharedEventGroup, socksProxyConfig = socksProxyConfig)
|
||||||
val bridgeName: String get() = getBridgeName(queueName, target)
|
val bridgeName: String get() = getBridgeName(queueName, target)
|
||||||
private val lock = ReentrantLock() // lock to serialise session level access
|
private val lock = ReentrantLock() // lock to serialise session level access
|
||||||
private var session: ClientSession? = null
|
private var session: ClientSession? = null
|
||||||
@ -181,7 +183,7 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val socksProxyConf
|
|||||||
if (bridgeExists(getBridgeName(queueName, target))) {
|
if (bridgeExists(getBridgeName(queueName, target))) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val newBridge = AMQPBridge(queueName, target, legalNames, keyStore, keyStorePrivateKeyPassword, trustStore, sharedEventLoopGroup!!, socksProxyConfig, artemis!!)
|
val newBridge = AMQPBridge(queueName, target, legalNames, keyStore, keyStorePrivateKeyPassword, trustStore, crlCheckSoftFail, sharedEventLoopGroup!!, socksProxyConfig, artemis!!)
|
||||||
lock.withLock {
|
lock.withLock {
|
||||||
bridgeNameToBridgeMap[newBridge.bridgeName] = newBridge
|
bridgeNameToBridgeMap[newBridge.bridgeName] = newBridge
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ interface SSLConfiguration {
|
|||||||
// TODO This looks like it should be in NodeSSLConfiguration
|
// TODO This looks like it should be in NodeSSLConfiguration
|
||||||
val nodeKeystore: Path get() = certificatesDirectory / "nodekeystore.jks"
|
val nodeKeystore: Path get() = certificatesDirectory / "nodekeystore.jks"
|
||||||
val trustStoreFile: Path get() = certificatesDirectory / "truststore.jks"
|
val trustStoreFile: Path get() = certificatesDirectory / "truststore.jks"
|
||||||
|
val crlCheckSoftFail: Boolean
|
||||||
|
|
||||||
fun loadTrustStore(createNew: Boolean = false): X509KeyStore {
|
fun loadTrustStore(createNew: Boolean = false): X509KeyStore {
|
||||||
return X509KeyStore.fromFile(trustStoreFile, trustStorePassword, createNew)
|
return X509KeyStore.fromFile(trustStoreFile, trustStorePassword, createNew)
|
||||||
|
@ -158,7 +158,7 @@ object X509Utilities {
|
|||||||
* @param crlDistPoint CRL distribution point.
|
* @param crlDistPoint CRL distribution point.
|
||||||
* @param crlIssuer X500Name of the CRL issuer.
|
* @param crlIssuer X500Name of the CRL issuer.
|
||||||
*/
|
*/
|
||||||
private fun createPartialCertificate(certificateType: CertificateType,
|
fun createPartialCertificate(certificateType: CertificateType,
|
||||||
issuer: X500Principal,
|
issuer: X500Principal,
|
||||||
issuerPublicKey: PublicKey,
|
issuerPublicKey: PublicKey,
|
||||||
subject: X500Principal,
|
subject: X500Principal,
|
||||||
|
@ -64,6 +64,7 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
|
|||||||
private val keyStore: KeyStore,
|
private val keyStore: KeyStore,
|
||||||
private val keyStorePrivateKeyPassword: String,
|
private val keyStorePrivateKeyPassword: String,
|
||||||
private val trustStore: KeyStore,
|
private val trustStore: KeyStore,
|
||||||
|
private val crlCheckSoftFail: Boolean,
|
||||||
private val trace: Boolean = false,
|
private val trace: Boolean = false,
|
||||||
private val sharedThreadPool: EventLoopGroup? = null,
|
private val sharedThreadPool: EventLoopGroup? = null,
|
||||||
private val socksProxyConfig: SocksProxyConfig? = null) : AutoCloseable {
|
private val socksProxyConfig: SocksProxyConfig? = null) : AutoCloseable {
|
||||||
@ -129,7 +130,7 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
keyManagerFactory.init(parent.keyStore, parent.keyStorePrivateKeyPassword.toCharArray())
|
keyManagerFactory.init(parent.keyStore, parent.keyStorePrivateKeyPassword.toCharArray())
|
||||||
trustManagerFactory.init(parent.trustStore)
|
trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(parent.trustStore, parent.crlCheckSoftFail))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initChannel(ch: SocketChannel) {
|
override fun initChannel(ch: SocketChannel) {
|
||||||
@ -178,9 +179,7 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
|
|||||||
private fun restart() {
|
private fun restart() {
|
||||||
val bootstrap = Bootstrap()
|
val bootstrap = Bootstrap()
|
||||||
// TODO Needs more configuration control when we profile. e.g. to use EPOLL on Linux
|
// TODO Needs more configuration control when we profile. e.g. to use EPOLL on Linux
|
||||||
bootstrap.group(workerGroup).
|
bootstrap.group(workerGroup).channel(NioSocketChannel::class.java).handler(ClientChannelInitializer(this))
|
||||||
channel(NioSocketChannel::class.java).
|
|
||||||
handler(ClientChannelInitializer(this))
|
|
||||||
currentTarget = targets[targetIndex]
|
currentTarget = targets[targetIndex]
|
||||||
val clientFuture = bootstrap.connect(currentTarget.host, currentTarget.port)
|
val clientFuture = bootstrap.connect(currentTarget.host, currentTarget.port)
|
||||||
clientFuture.addListener(connectListener)
|
clientFuture.addListener(connectListener)
|
||||||
|
@ -50,6 +50,7 @@ class AMQPServer(val hostName: String,
|
|||||||
private val keyStore: KeyStore,
|
private val keyStore: KeyStore,
|
||||||
private val keyStorePrivateKeyPassword: CharArray,
|
private val keyStorePrivateKeyPassword: CharArray,
|
||||||
private val trustStore: KeyStore,
|
private val trustStore: KeyStore,
|
||||||
|
private val crlCheckSoftFail: Boolean,
|
||||||
private val trace: Boolean = false) : AutoCloseable {
|
private val trace: Boolean = false) : AutoCloseable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -76,7 +77,8 @@ class AMQPServer(val hostName: String,
|
|||||||
keyStore: KeyStore,
|
keyStore: KeyStore,
|
||||||
keyStorePrivateKeyPassword: String,
|
keyStorePrivateKeyPassword: String,
|
||||||
trustStore: KeyStore,
|
trustStore: KeyStore,
|
||||||
trace: Boolean = false) : this(hostName, port, userName, password, keyStore, keyStorePrivateKeyPassword.toCharArray(), trustStore, trace)
|
crlCheckSoftFail: Boolean,
|
||||||
|
trace: Boolean = false) : this(hostName, port, userName, password, keyStore, keyStorePrivateKeyPassword.toCharArray(), trustStore, crlCheckSoftFail, trace)
|
||||||
|
|
||||||
private class ServerChannelInitializer(val parent: AMQPServer) : ChannelInitializer<SocketChannel>() {
|
private class ServerChannelInitializer(val parent: AMQPServer) : ChannelInitializer<SocketChannel>() {
|
||||||
private val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
|
private val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
|
||||||
@ -84,7 +86,7 @@ class AMQPServer(val hostName: String,
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
keyManagerFactory.init(parent.keyStore, parent.keyStorePrivateKeyPassword)
|
keyManagerFactory.init(parent.keyStore, parent.keyStorePrivateKeyPassword)
|
||||||
trustManagerFactory.init(parent.trustStore)
|
trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(parent.trustStore, parent.crlCheckSoftFail))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initChannel(ch: SocketChannel) {
|
override fun initChannel(ch: SocketChannel) {
|
||||||
@ -118,11 +120,7 @@ class AMQPServer(val hostName: String,
|
|||||||
|
|
||||||
val server = ServerBootstrap()
|
val server = ServerBootstrap()
|
||||||
// TODO Needs more configuration control when we profile. e.g. to use EPOLL on Linux
|
// TODO Needs more configuration control when we profile. e.g. to use EPOLL on Linux
|
||||||
server.group(bossGroup, workerGroup).
|
server.group(bossGroup, workerGroup).channel(NioServerSocketChannel::class.java).option(ChannelOption.SO_BACKLOG, 100).handler(LoggingHandler(LogLevel.INFO)).childHandler(ServerChannelInitializer(this))
|
||||||
channel(NioServerSocketChannel::class.java).
|
|
||||||
option(ChannelOption.SO_BACKLOG, 100).
|
|
||||||
handler(LoggingHandler(LogLevel.INFO)).
|
|
||||||
childHandler(ServerChannelInitializer(this))
|
|
||||||
|
|
||||||
log.info("Try to bind $port")
|
log.info("Try to bind $port")
|
||||||
val channelFuture = server.bind(hostName, port).sync() // block/throw here as better to know we failed to claim port than carry on
|
val channelFuture = server.bind(hostName, port).sync() // block/throw here as better to know we failed to claim port than carry on
|
||||||
|
@ -13,10 +13,14 @@ package net.corda.nodeapi.internal.protonwrapper.netty
|
|||||||
import io.netty.handler.ssl.SslHandler
|
import io.netty.handler.ssl.SslHandler
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.nodeapi.ArtemisTcpTransport
|
import net.corda.nodeapi.ArtemisTcpTransport
|
||||||
|
import java.security.KeyStore
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import javax.net.ssl.KeyManagerFactory
|
import java.security.cert.CertPathBuilder
|
||||||
import javax.net.ssl.SSLContext
|
import java.security.cert.PKIXBuilderParameters
|
||||||
import javax.net.ssl.TrustManagerFactory
|
import java.security.cert.PKIXRevocationChecker
|
||||||
|
import java.security.cert.X509CertSelector
|
||||||
|
import java.util.*
|
||||||
|
import javax.net.ssl.*
|
||||||
|
|
||||||
internal fun createClientSslHelper(target: NetworkHostAndPort,
|
internal fun createClientSslHelper(target: NetworkHostAndPort,
|
||||||
keyManagerFactory: KeyManagerFactory,
|
keyManagerFactory: KeyManagerFactory,
|
||||||
@ -46,4 +50,22 @@ internal fun createServerSslHelper(keyManagerFactory: KeyManagerFactory,
|
|||||||
sslEngine.enabledCipherSuites = ArtemisTcpTransport.CIPHER_SUITES.toTypedArray()
|
sslEngine.enabledCipherSuites = ArtemisTcpTransport.CIPHER_SUITES.toTypedArray()
|
||||||
sslEngine.enableSessionCreation = true
|
sslEngine.enableSessionCreation = true
|
||||||
return SslHandler(sslEngine)
|
return SslHandler(sslEngine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun initialiseTrustStoreAndEnableCrlChecking(trustStore: KeyStore, crlCheckSoftFail: Boolean): ManagerFactoryParameters {
|
||||||
|
val certPathBuilder = CertPathBuilder.getInstance("PKIX")
|
||||||
|
val revocationChecker = certPathBuilder.revocationChecker as PKIXRevocationChecker
|
||||||
|
revocationChecker.options = EnumSet.of(
|
||||||
|
// Prefer CRL over OCSP
|
||||||
|
PKIXRevocationChecker.Option.PREFER_CRLS,
|
||||||
|
// Don't fall back to OCSP checking
|
||||||
|
PKIXRevocationChecker.Option.NO_FALLBACK)
|
||||||
|
if (crlCheckSoftFail) {
|
||||||
|
// Allow revocation check to succeed if the revocation status cannot be determined for one of
|
||||||
|
// the following reasons: The CRL or OCSP response cannot be obtained because of a network error.
|
||||||
|
revocationChecker.options = revocationChecker.options + PKIXRevocationChecker.Option.SOFT_FAIL
|
||||||
|
}
|
||||||
|
val pkixParams = PKIXBuilderParameters(trustStore, X509CertSelector())
|
||||||
|
pkixParams.addCertPathChecker(revocationChecker)
|
||||||
|
return CertPathTrustManagerParameters(pkixParams)
|
||||||
|
}
|
||||||
|
@ -193,6 +193,7 @@ class X509UtilitiesTest {
|
|||||||
override val certificatesDirectory = tempFolder.root.toPath()
|
override val certificatesDirectory = tempFolder.root.toPath()
|
||||||
override val keyStorePassword = "serverstorepass"
|
override val keyStorePassword = "serverstorepass"
|
||||||
override val trustStorePassword = "trustpass"
|
override val trustStorePassword = "trustpass"
|
||||||
|
override val crlCheckSoftFail: Boolean = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||||
@ -228,6 +229,7 @@ class X509UtilitiesTest {
|
|||||||
override val certificatesDirectory = tempFolder.root.toPath()
|
override val certificatesDirectory = tempFolder.root.toPath()
|
||||||
override val keyStorePassword = "serverstorepass"
|
override val keyStorePassword = "serverstorepass"
|
||||||
override val trustStorePassword = "trustpass"
|
override val trustStorePassword = "trustpass"
|
||||||
|
override val crlCheckSoftFail: Boolean = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
|
||||||
|
@ -55,6 +55,7 @@ class NodeKeystoreCheckTest : IntegrationTest() {
|
|||||||
override val keyStorePassword: String = keystorePassword
|
override val keyStorePassword: String = keystorePassword
|
||||||
override val trustStorePassword: String = keystorePassword
|
override val trustStorePassword: String = keystorePassword
|
||||||
override val certificatesDirectory: Path = baseDirectory(ALICE_NAME) / "certificates"
|
override val certificatesDirectory: Path = baseDirectory(ALICE_NAME) / "certificates"
|
||||||
|
override val crlCheckSoftFail: Boolean = true
|
||||||
}
|
}
|
||||||
config.configureDevKeyAndTrustStores(ALICE_NAME)
|
config.configureDevKeyAndTrustStores(ALICE_NAME)
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ class AMQPBridgeTest {
|
|||||||
|
|
||||||
fun formatMessage(expected: String, actual: Int, received: List<Int>): String {
|
fun formatMessage(expected: String, actual: Int, received: List<Int>): String {
|
||||||
return "Expected message with id $expected, got $actual, previous message receive sequence: " +
|
return "Expected message with id $expected, got $actual, previous message receive sequence: " +
|
||||||
"${received.joinToString(", ", "[", "]")}."
|
"${received.joinToString(", ", "[", "]")}."
|
||||||
}
|
}
|
||||||
|
|
||||||
val received1 = receive.next()
|
val received1 = receive.next()
|
||||||
@ -251,6 +251,7 @@ class AMQPBridgeTest {
|
|||||||
doReturn(temporaryFolder.root.toPath() / "artemis").whenever(it).baseDirectory
|
doReturn(temporaryFolder.root.toPath() / "artemis").whenever(it).baseDirectory
|
||||||
doReturn(ALICE_NAME).whenever(it).myLegalName
|
doReturn(ALICE_NAME).whenever(it).myLegalName
|
||||||
doReturn("trustpass").whenever(it).trustStorePassword
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
|
doReturn(true).whenever(it).crlCheckSoftFail
|
||||||
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
doReturn(artemisAddress).whenever(it).p2pAddress
|
doReturn(artemisAddress).whenever(it).p2pAddress
|
||||||
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
||||||
@ -311,6 +312,7 @@ class AMQPBridgeTest {
|
|||||||
serverConfig.loadSslKeyStore().internal,
|
serverConfig.loadSslKeyStore().internal,
|
||||||
serverConfig.keyStorePassword,
|
serverConfig.keyStorePassword,
|
||||||
serverConfig.loadTrustStore().internal,
|
serverConfig.loadTrustStore().internal,
|
||||||
|
crlCheckSoftFail = true,
|
||||||
trace = true
|
trace = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,473 @@
|
|||||||
|
package net.corda.node.amqp
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
|
import net.corda.core.crypto.Crypto
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.toFuture
|
||||||
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
|
import net.corda.core.utilities.days
|
||||||
|
import net.corda.core.utilities.minutes
|
||||||
|
import net.corda.core.utilities.seconds
|
||||||
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
|
import net.corda.node.services.config.configureWithDevSSLCertificate
|
||||||
|
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2P_PREFIX
|
||||||
|
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER
|
||||||
|
import net.corda.nodeapi.internal.config.SSLConfiguration
|
||||||
|
import net.corda.nodeapi.internal.crypto.*
|
||||||
|
import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus
|
||||||
|
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient
|
||||||
|
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer
|
||||||
|
import net.corda.testing.core.ALICE_NAME
|
||||||
|
import net.corda.testing.core.BOB_NAME
|
||||||
|
import net.corda.testing.core.CHARLIE_NAME
|
||||||
|
import net.corda.testing.core.freePort
|
||||||
|
import net.corda.testing.internal.DEV_INTERMEDIATE_CA
|
||||||
|
import net.corda.testing.internal.DEV_ROOT_CA
|
||||||
|
import net.corda.testing.internal.rigorousMock
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x509.*
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509v2CRLBuilder
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||||
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
|
||||||
|
import org.eclipse.jetty.server.Server
|
||||||
|
import org.eclipse.jetty.server.ServerConnector
|
||||||
|
import org.eclipse.jetty.server.handler.HandlerCollection
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder
|
||||||
|
import org.glassfish.jersey.server.ResourceConfig
|
||||||
|
import org.glassfish.jersey.servlet.ServletContainer
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import java.security.KeyPair
|
||||||
|
import java.security.PrivateKey
|
||||||
|
import java.security.Security
|
||||||
|
import java.security.cert.X509CRL
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import java.util.*
|
||||||
|
import javax.ws.rs.GET
|
||||||
|
import javax.ws.rs.Path
|
||||||
|
import javax.ws.rs.Produces
|
||||||
|
import javax.ws.rs.core.Response
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class CertificateRevocationListNodeTests {
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
val temporaryFolder = TemporaryFolder()
|
||||||
|
|
||||||
|
private val ROOT_CA = DEV_ROOT_CA
|
||||||
|
private lateinit var INTERMEDIATE_CA: CertificateAndKeyPair
|
||||||
|
|
||||||
|
private val serverPort = freePort()
|
||||||
|
|
||||||
|
private lateinit var server: CrlServer
|
||||||
|
|
||||||
|
private val revokedNodeCerts: MutableList<BigInteger> = mutableListOf()
|
||||||
|
private val revokedIntermediateCerts: MutableList<BigInteger> = mutableListOf()
|
||||||
|
|
||||||
|
private abstract class AbstractNodeConfiguration : NodeConfiguration
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
Security.addProvider(BouncyCastleProvider())
|
||||||
|
revokedNodeCerts.clear()
|
||||||
|
server = CrlServer(NetworkHostAndPort("localhost", 0))
|
||||||
|
server.start()
|
||||||
|
INTERMEDIATE_CA = CertificateAndKeyPair(replaceCrlDistPointCaCertificate(
|
||||||
|
DEV_INTERMEDIATE_CA.certificate,
|
||||||
|
CertificateType.INTERMEDIATE_CA,
|
||||||
|
ROOT_CA.keyPair,
|
||||||
|
"http://${server.hostAndPort}/crl/intermediate.crl"), DEV_INTERMEDIATE_CA.keyPair)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun tearDown() {
|
||||||
|
server.close()
|
||||||
|
revokedNodeCerts.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Simple AMPQ Client to Server connection works`() {
|
||||||
|
val crlCheckSoftFail = true
|
||||||
|
val (amqpServer, _) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail)
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
val receiveSubs = amqpServer.onReceive.subscribe {
|
||||||
|
assertEquals(BOB_NAME.toString(), it.sourceLegalName)
|
||||||
|
assertEquals(P2P_PREFIX + "Test", it.topic)
|
||||||
|
assertEquals("Test", String(it.payload))
|
||||||
|
it.complete(true)
|
||||||
|
}
|
||||||
|
val (amqpClient, _) = createClient(serverPort, crlCheckSoftFail)
|
||||||
|
amqpClient.use {
|
||||||
|
val serverConnected = amqpServer.onConnection.toFuture()
|
||||||
|
val clientConnected = amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val serverConnect = serverConnected.get()
|
||||||
|
assertEquals(true, serverConnect.connected)
|
||||||
|
val clientConnect = clientConnected.get()
|
||||||
|
assertEquals(true, clientConnect.connected)
|
||||||
|
val msg = amqpClient.createMessage("Test".toByteArray(),
|
||||||
|
P2P_PREFIX + "Test",
|
||||||
|
ALICE_NAME.toString(),
|
||||||
|
emptyMap())
|
||||||
|
amqpClient.write(msg)
|
||||||
|
assertEquals(MessageStatus.Acknowledged, msg.onComplete.get())
|
||||||
|
receiveSubs.unsubscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `AMPQ Client to Server connection fails when client's certificate is revoked`() {
|
||||||
|
val crlCheckSoftFail = true
|
||||||
|
val (amqpServer, _) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail)
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
amqpServer.onReceive.subscribe {
|
||||||
|
it.complete(true)
|
||||||
|
}
|
||||||
|
val (amqpClient, clientCert) = createClient(serverPort, crlCheckSoftFail)
|
||||||
|
revokedNodeCerts.add(clientCert.serialNumber)
|
||||||
|
amqpClient.use {
|
||||||
|
val serverConnected = amqpServer.onConnection.toFuture()
|
||||||
|
amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val serverConnect = serverConnected.get()
|
||||||
|
assertEquals(false, serverConnect.connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `AMPQ Client to Server connection fails when servers's certificate is revoked`() {
|
||||||
|
val crlCheckSoftFail = true
|
||||||
|
val (amqpServer, serverCert) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail)
|
||||||
|
revokedNodeCerts.add(serverCert.serialNumber)
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
amqpServer.onReceive.subscribe {
|
||||||
|
it.complete(true)
|
||||||
|
}
|
||||||
|
val (amqpClient, _) = createClient(serverPort, crlCheckSoftFail)
|
||||||
|
amqpClient.use {
|
||||||
|
val serverConnected = amqpServer.onConnection.toFuture()
|
||||||
|
amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val serverConnect = serverConnected.get()
|
||||||
|
assertEquals(false, serverConnect.connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `AMPQ Client to Server connection fails when servers's certificate is revoked and soft fail is enabled`() {
|
||||||
|
val crlCheckSoftFail = true
|
||||||
|
val (amqpServer, serverCert) = createServer(serverPort, crlCheckSoftFail = crlCheckSoftFail)
|
||||||
|
revokedNodeCerts.add(serverCert.serialNumber)
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
amqpServer.onReceive.subscribe {
|
||||||
|
it.complete(true)
|
||||||
|
}
|
||||||
|
val (amqpClient, _) = createClient(serverPort, crlCheckSoftFail)
|
||||||
|
amqpClient.use {
|
||||||
|
val serverConnected = amqpServer.onConnection.toFuture()
|
||||||
|
amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val serverConnect = serverConnected.get()
|
||||||
|
assertEquals(false, serverConnect.connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `AMPQ Client to Server connection succeeds when CRL cannot be obtained and soft fail is enabled`() {
|
||||||
|
val crlCheckSoftFail = true
|
||||||
|
val (amqpServer, serverCert) = createServer(
|
||||||
|
serverPort,
|
||||||
|
crlCheckSoftFail = crlCheckSoftFail,
|
||||||
|
nodeCrlDistPoint = "http://${server.hostAndPort}/crl/invalid.crl")
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
amqpServer.onReceive.subscribe {
|
||||||
|
it.complete(true)
|
||||||
|
}
|
||||||
|
val (amqpClient, _) = createClient(
|
||||||
|
serverPort,
|
||||||
|
crlCheckSoftFail,
|
||||||
|
nodeCrlDistPoint = "http://${server.hostAndPort}/crl/invalid.crl")
|
||||||
|
amqpClient.use {
|
||||||
|
val serverConnected = amqpServer.onConnection.toFuture()
|
||||||
|
amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val serverConnect = serverConnected.get()
|
||||||
|
assertEquals(true, serverConnect.connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Revocation status chceck fails when the CRL distribution point is not set and soft fail is disabled`() {
|
||||||
|
val crlCheckSoftFail = false
|
||||||
|
val (amqpServer, _) = createServer(
|
||||||
|
serverPort,
|
||||||
|
crlCheckSoftFail = crlCheckSoftFail,
|
||||||
|
tlsCrlDistPoint = null)
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
amqpServer.onReceive.subscribe {
|
||||||
|
it.complete(true)
|
||||||
|
}
|
||||||
|
val (amqpClient, _) = createClient(
|
||||||
|
serverPort,
|
||||||
|
crlCheckSoftFail,
|
||||||
|
tlsCrlDistPoint = null)
|
||||||
|
amqpClient.use {
|
||||||
|
val serverConnected = amqpServer.onConnection.toFuture()
|
||||||
|
amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val serverConnect = serverConnected.get()
|
||||||
|
assertEquals(false, serverConnect.connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Revocation status chceck succeds when the CRL distribution point is not set and soft fail is enabled`() {
|
||||||
|
val crlCheckSoftFail = true
|
||||||
|
val (amqpServer, _) = createServer(
|
||||||
|
serverPort,
|
||||||
|
crlCheckSoftFail = crlCheckSoftFail,
|
||||||
|
tlsCrlDistPoint = null)
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
amqpServer.onReceive.subscribe {
|
||||||
|
it.complete(true)
|
||||||
|
}
|
||||||
|
val (amqpClient, _) = createClient(
|
||||||
|
serverPort,
|
||||||
|
crlCheckSoftFail,
|
||||||
|
tlsCrlDistPoint = null)
|
||||||
|
amqpClient.use {
|
||||||
|
val serverConnected = amqpServer.onConnection.toFuture()
|
||||||
|
amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val serverConnect = serverConnected.get()
|
||||||
|
assertEquals(true, serverConnect.connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createClient(targetPort: Int,
|
||||||
|
crlCheckSoftFail: Boolean,
|
||||||
|
nodeCrlDistPoint: String = "http://${server.hostAndPort}/crl/node.crl",
|
||||||
|
tlsCrlDistPoint: String? = "http://${server.hostAndPort}/crl/empty.crl"): Pair<AMQPClient, X509Certificate> {
|
||||||
|
val clientConfig = rigorousMock<AbstractNodeConfiguration>().also {
|
||||||
|
doReturn(temporaryFolder.root.toPath() / "client").whenever(it).baseDirectory
|
||||||
|
doReturn(BOB_NAME).whenever(it).myLegalName
|
||||||
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
|
doReturn(crlCheckSoftFail).whenever(it).crlCheckSoftFail
|
||||||
|
}
|
||||||
|
clientConfig.configureWithDevSSLCertificate()
|
||||||
|
val nodeCert = clientConfig.recreateNodeCaAndTlsCertificates(nodeCrlDistPoint, tlsCrlDistPoint)
|
||||||
|
val clientTruststore = clientConfig.loadTrustStore().internal
|
||||||
|
val clientKeystore = clientConfig.loadSslKeyStore().internal
|
||||||
|
return Pair(AMQPClient(
|
||||||
|
listOf(NetworkHostAndPort("localhost", targetPort)),
|
||||||
|
setOf(ALICE_NAME, CHARLIE_NAME),
|
||||||
|
PEER_USER,
|
||||||
|
PEER_USER,
|
||||||
|
clientKeystore,
|
||||||
|
clientConfig.keyStorePassword,
|
||||||
|
clientTruststore,
|
||||||
|
crlCheckSoftFail), nodeCert)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createServer(port: Int, name: CordaX500Name = ALICE_NAME,
|
||||||
|
crlCheckSoftFail: Boolean,
|
||||||
|
nodeCrlDistPoint: String = "http://${server.hostAndPort}/crl/node.crl",
|
||||||
|
tlsCrlDistPoint: String? = "http://${server.hostAndPort}/crl/empty.crl"): Pair<AMQPServer, X509Certificate> {
|
||||||
|
val serverConfig = rigorousMock<AbstractNodeConfiguration>().also {
|
||||||
|
doReturn(temporaryFolder.root.toPath() / "server").whenever(it).baseDirectory
|
||||||
|
doReturn(name).whenever(it).myLegalName
|
||||||
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
|
doReturn(crlCheckSoftFail).whenever(it).crlCheckSoftFail
|
||||||
|
}
|
||||||
|
serverConfig.configureWithDevSSLCertificate()
|
||||||
|
val nodeCert = serverConfig.recreateNodeCaAndTlsCertificates(nodeCrlDistPoint, tlsCrlDistPoint)
|
||||||
|
val serverTruststore = serverConfig.loadTrustStore().internal
|
||||||
|
val serverKeystore = serverConfig.loadSslKeyStore().internal
|
||||||
|
return Pair(AMQPServer(
|
||||||
|
"0.0.0.0",
|
||||||
|
port,
|
||||||
|
PEER_USER,
|
||||||
|
PEER_USER,
|
||||||
|
serverKeystore,
|
||||||
|
serverConfig.keyStorePassword,
|
||||||
|
serverTruststore,
|
||||||
|
crlCheckSoftFail), nodeCert)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SSLConfiguration.recreateNodeCaAndTlsCertificates(nodeCaCrlDistPoint: String, tlsCrlDistPoint: String?): X509Certificate {
|
||||||
|
val nodeKeyStore = loadNodeKeyStore()
|
||||||
|
val (nodeCert, nodeKeys) = nodeKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_CA)
|
||||||
|
val newNodeCert = replaceCrlDistPointCaCertificate(nodeCert, CertificateType.NODE_CA, INTERMEDIATE_CA.keyPair, nodeCaCrlDistPoint)
|
||||||
|
val nodeCertChain = listOf(newNodeCert, INTERMEDIATE_CA.certificate, *nodeKeyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_CA).drop(2).toTypedArray())
|
||||||
|
nodeKeyStore.internal.deleteEntry(X509Utilities.CORDA_CLIENT_CA)
|
||||||
|
nodeKeyStore.save()
|
||||||
|
nodeKeyStore.update {
|
||||||
|
setPrivateKey(X509Utilities.CORDA_CLIENT_CA, nodeKeys.private, nodeCertChain)
|
||||||
|
}
|
||||||
|
val sslKeyStore = loadSslKeyStore()
|
||||||
|
val (tlsCert, tlsKeys) = sslKeyStore.getCertificateAndKeyPair(X509Utilities.CORDA_CLIENT_TLS)
|
||||||
|
val newTlsCert = replaceCrlDistPointCaCertificate(tlsCert, CertificateType.TLS, nodeKeys, tlsCrlDistPoint, X500Name.getInstance(ROOT_CA.certificate.subjectX500Principal.encoded))
|
||||||
|
val sslCertChain = listOf(newTlsCert, newNodeCert, INTERMEDIATE_CA.certificate, *sslKeyStore.getCertificateChain(X509Utilities.CORDA_CLIENT_TLS).drop(3).toTypedArray())
|
||||||
|
sslKeyStore.internal.deleteEntry(X509Utilities.CORDA_CLIENT_TLS)
|
||||||
|
sslKeyStore.save()
|
||||||
|
sslKeyStore.update {
|
||||||
|
setPrivateKey(X509Utilities.CORDA_CLIENT_TLS, tlsKeys.private, sslCertChain)
|
||||||
|
}
|
||||||
|
return newNodeCert
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceCrlDistPointCaCertificate(currentCaCert: X509Certificate, certType: CertificateType, issuerKeyPair: KeyPair, crlDistPoint: String?, crlIssuer: X500Name? = null): X509Certificate {
|
||||||
|
val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private)
|
||||||
|
val provider = Crypto.findProvider(signatureScheme.providerName)
|
||||||
|
val issuerSigner = ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider)
|
||||||
|
val builder = X509Utilities.createPartialCertificate(
|
||||||
|
certType,
|
||||||
|
currentCaCert.issuerX500Principal,
|
||||||
|
issuerKeyPair.public,
|
||||||
|
currentCaCert.subjectX500Principal,
|
||||||
|
currentCaCert.publicKey,
|
||||||
|
Pair(Date(System.currentTimeMillis() - 5.minutes.toMillis()), Date(System.currentTimeMillis() + 10.days.toMillis())),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
crlDistPoint?.let {
|
||||||
|
val distPointName = DistributionPointName(GeneralNames(GeneralName(GeneralName.uniformResourceIdentifier, it)))
|
||||||
|
val crlIssuerGeneralNames = crlIssuer?.let {
|
||||||
|
GeneralNames(GeneralName(crlIssuer))
|
||||||
|
}
|
||||||
|
val distPoint = DistributionPoint(distPointName, null, crlIssuerGeneralNames)
|
||||||
|
builder.addExtension(Extension.cRLDistributionPoints, false, CRLDistPoint(arrayOf(distPoint)))
|
||||||
|
}
|
||||||
|
return builder.build(issuerSigner).toJca()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("crl")
|
||||||
|
inner class CrlServlet(private val server: CrlServer) {
|
||||||
|
|
||||||
|
private val SIGNATURE_ALGORITHM = "SHA256withECDSA"
|
||||||
|
private val NODE_CRL = "node.crl"
|
||||||
|
private val INTEMEDIATE_CRL = "intermediate.crl"
|
||||||
|
private val EMPTY_CRL = "empty.crl"
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("node.crl")
|
||||||
|
@Produces("application/pkcs7-crl")
|
||||||
|
fun getNodeCRL(): Response {
|
||||||
|
return Response.ok(createRevocationList(
|
||||||
|
INTERMEDIATE_CA.certificate,
|
||||||
|
INTERMEDIATE_CA.keyPair.private,
|
||||||
|
NODE_CRL,
|
||||||
|
false,
|
||||||
|
*revokedNodeCerts.toTypedArray()).encoded).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("intermediate.crl")
|
||||||
|
@Produces("application/pkcs7-crl")
|
||||||
|
fun getIntermediateCRL(): Response {
|
||||||
|
return Response.ok(createRevocationList(
|
||||||
|
ROOT_CA.certificate,
|
||||||
|
ROOT_CA.keyPair.private,
|
||||||
|
INTEMEDIATE_CRL,
|
||||||
|
false,
|
||||||
|
*revokedIntermediateCerts.toTypedArray()).encoded).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("empty.crl")
|
||||||
|
@Produces("application/pkcs7-crl")
|
||||||
|
fun getEmptyCRL(): Response {
|
||||||
|
return Response.ok(createRevocationList(
|
||||||
|
ROOT_CA.certificate,
|
||||||
|
ROOT_CA.keyPair.private,
|
||||||
|
EMPTY_CRL, true).encoded).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRevocationList(caCertificate: X509Certificate,
|
||||||
|
caPrivateKey: PrivateKey,
|
||||||
|
endpoint: String,
|
||||||
|
indirect: Boolean,
|
||||||
|
vararg serialNumbers: BigInteger): X509CRL {
|
||||||
|
println("Generating CRL for $endpoint")
|
||||||
|
val builder = JcaX509v2CRLBuilder(caCertificate.subjectX500Principal, Date(System.currentTimeMillis() - 1.minutes.toMillis()))
|
||||||
|
val extensionUtils = JcaX509ExtensionUtils()
|
||||||
|
builder.addExtension(Extension.authorityKeyIdentifier,
|
||||||
|
false, extensionUtils.createAuthorityKeyIdentifier(caCertificate))
|
||||||
|
val issuingDistPointName = GeneralName(
|
||||||
|
GeneralName.uniformResourceIdentifier,
|
||||||
|
"http://${server.hostAndPort.host}:${server.hostAndPort.port}/crl/$endpoint")
|
||||||
|
// This is required and needs to match the certificate settings with respect to being indirect
|
||||||
|
val issuingDistPoint = IssuingDistributionPoint(DistributionPointName(GeneralNames(issuingDistPointName)), indirect, false)
|
||||||
|
builder.addExtension(Extension.issuingDistributionPoint, true, issuingDistPoint)
|
||||||
|
builder.setNextUpdate(Date(System.currentTimeMillis() + 1.seconds.toMillis()))
|
||||||
|
serialNumbers.forEach {
|
||||||
|
builder.addCRLEntry(it, Date(System.currentTimeMillis() - 10.minutes.toMillis()), ReasonFlags.certificateHold)
|
||||||
|
}
|
||||||
|
val signer = JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(caPrivateKey)
|
||||||
|
return JcaX509CRLConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCRL(builder.build(signer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class CrlServer(hostAndPort: NetworkHostAndPort) : Closeable {
|
||||||
|
|
||||||
|
private val server: Server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply {
|
||||||
|
handler = HandlerCollection().apply {
|
||||||
|
addHandler(buildServletContextHandler())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hostAndPort: NetworkHostAndPort
|
||||||
|
get() = server.connectors.mapNotNull { it as? ServerConnector }
|
||||||
|
.map { NetworkHostAndPort(it.host, it.localPort) }
|
||||||
|
.first()
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
println("Shutting down network management web services...")
|
||||||
|
server.stop()
|
||||||
|
server.join()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
server.start()
|
||||||
|
println("Network management web services started on $hostAndPort")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildServletContextHandler(): ServletContextHandler {
|
||||||
|
val crlServer = this
|
||||||
|
return ServletContextHandler().apply {
|
||||||
|
contextPath = "/"
|
||||||
|
val resourceConfig = ResourceConfig().apply {
|
||||||
|
register(CrlServlet(crlServer))
|
||||||
|
}
|
||||||
|
val jerseyServlet = ServletHolder(ServletContainer(resourceConfig)).apply { initOrder = 0 }
|
||||||
|
addServlet(jerseyServlet, "/*")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -79,6 +79,21 @@ class ProtonWrapperTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `AMPQ Client fails to connect when crl soft fail check is disabled`() {
|
||||||
|
val amqpServer = createServer(serverPort, CordaX500Name("Rogue 1", "London", "GB"), false)
|
||||||
|
amqpServer.use {
|
||||||
|
amqpServer.start()
|
||||||
|
val amqpClient = createClient()
|
||||||
|
amqpClient.use {
|
||||||
|
val clientConnected = amqpClient.onConnection.toFuture()
|
||||||
|
amqpClient.start()
|
||||||
|
val clientConnect = clientConnected.get()
|
||||||
|
assertEquals(false, clientConnect.connected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `AMPQ Client refuses to connect to unexpected server`() {
|
fun `AMPQ Client refuses to connect to unexpected server`() {
|
||||||
val amqpServer = createServer(serverPort, CordaX500Name("Rogue 1", "London", "GB"))
|
val amqpServer = createServer(serverPort, CordaX500Name("Rogue 1", "London", "GB"))
|
||||||
@ -233,6 +248,7 @@ class ProtonWrapperTests {
|
|||||||
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
doReturn(null).whenever(it).jmxMonitoringHttpPort
|
||||||
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
|
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
|
||||||
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000))).whenever(it).enterpriseConfiguration
|
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000))).whenever(it).enterpriseConfiguration
|
||||||
|
doReturn(true).whenever(it).crlCheckSoftFail
|
||||||
}
|
}
|
||||||
artemisConfig.configureWithDevSSLCertificate()
|
artemisConfig.configureWithDevSSLCertificate()
|
||||||
|
|
||||||
@ -249,6 +265,7 @@ class ProtonWrapperTests {
|
|||||||
doReturn(BOB_NAME).whenever(it).myLegalName
|
doReturn(BOB_NAME).whenever(it).myLegalName
|
||||||
doReturn("trustpass").whenever(it).trustStorePassword
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
|
doReturn(true).whenever(it).crlCheckSoftFail
|
||||||
}
|
}
|
||||||
clientConfig.configureWithDevSSLCertificate()
|
clientConfig.configureWithDevSSLCertificate()
|
||||||
|
|
||||||
@ -256,14 +273,15 @@ class ProtonWrapperTests {
|
|||||||
val clientKeystore = clientConfig.loadSslKeyStore().internal
|
val clientKeystore = clientConfig.loadSslKeyStore().internal
|
||||||
return AMQPClient(
|
return AMQPClient(
|
||||||
listOf(NetworkHostAndPort("localhost", serverPort),
|
listOf(NetworkHostAndPort("localhost", serverPort),
|
||||||
NetworkHostAndPort("localhost", serverPort2),
|
NetworkHostAndPort("localhost", serverPort2),
|
||||||
NetworkHostAndPort("localhost", artemisPort)),
|
NetworkHostAndPort("localhost", artemisPort)),
|
||||||
setOf(ALICE_NAME, CHARLIE_NAME),
|
setOf(ALICE_NAME, CHARLIE_NAME),
|
||||||
PEER_USER,
|
PEER_USER,
|
||||||
PEER_USER,
|
PEER_USER,
|
||||||
clientKeystore,
|
clientKeystore,
|
||||||
clientConfig.keyStorePassword,
|
clientConfig.keyStorePassword,
|
||||||
clientTruststore, true)
|
clientTruststore,
|
||||||
|
true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createSharedThreadsClient(sharedEventGroup: EventLoopGroup, id: Int): AMQPClient {
|
private fun createSharedThreadsClient(sharedEventGroup: EventLoopGroup, id: Int): AMQPClient {
|
||||||
@ -272,6 +290,7 @@ class ProtonWrapperTests {
|
|||||||
doReturn(CordaX500Name(null, "client $id", "Corda", "London", null, "GB")).whenever(it).myLegalName
|
doReturn(CordaX500Name(null, "client $id", "Corda", "London", null, "GB")).whenever(it).myLegalName
|
||||||
doReturn("trustpass").whenever(it).trustStorePassword
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
|
doReturn(true).whenever(it).crlCheckSoftFail
|
||||||
}
|
}
|
||||||
clientConfig.configureWithDevSSLCertificate()
|
clientConfig.configureWithDevSSLCertificate()
|
||||||
|
|
||||||
@ -284,15 +303,18 @@ class ProtonWrapperTests {
|
|||||||
PEER_USER,
|
PEER_USER,
|
||||||
clientKeystore,
|
clientKeystore,
|
||||||
clientConfig.keyStorePassword,
|
clientConfig.keyStorePassword,
|
||||||
clientTruststore, true, sharedEventGroup)
|
clientTruststore,
|
||||||
|
true,
|
||||||
|
sharedThreadPool = sharedEventGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createServer(port: Int, name: CordaX500Name = ALICE_NAME): AMQPServer {
|
private fun createServer(port: Int, name: CordaX500Name = ALICE_NAME, crlCheckSoftFail: Boolean = true): AMQPServer {
|
||||||
val serverConfig = rigorousMock<AbstractNodeConfiguration>().also {
|
val serverConfig = rigorousMock<AbstractNodeConfiguration>().also {
|
||||||
doReturn(temporaryFolder.root.toPath() / "server").whenever(it).baseDirectory
|
doReturn(temporaryFolder.root.toPath() / "server").whenever(it).baseDirectory
|
||||||
doReturn(name).whenever(it).myLegalName
|
doReturn(name).whenever(it).myLegalName
|
||||||
doReturn("trustpass").whenever(it).trustStorePassword
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
|
doReturn(crlCheckSoftFail).whenever(it).crlCheckSoftFail
|
||||||
}
|
}
|
||||||
serverConfig.configureWithDevSSLCertificate()
|
serverConfig.configureWithDevSSLCertificate()
|
||||||
|
|
||||||
@ -305,6 +327,7 @@ class ProtonWrapperTests {
|
|||||||
PEER_USER,
|
PEER_USER,
|
||||||
serverKeystore,
|
serverKeystore,
|
||||||
serverConfig.keyStorePassword,
|
serverConfig.keyStorePassword,
|
||||||
serverTruststore)
|
serverTruststore,
|
||||||
|
crlCheckSoftFail = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,7 +335,7 @@ class SocksTests {
|
|||||||
PEER_USER,
|
PEER_USER,
|
||||||
clientKeystore,
|
clientKeystore,
|
||||||
clientConfig.keyStorePassword,
|
clientConfig.keyStorePassword,
|
||||||
clientTruststore, true, sharedEventGroup,
|
clientTruststore, true, true, sharedEventGroup,
|
||||||
socksProxyConfig = SocksProxyConfig(SocksProxyVersion.SOCKS5, NetworkHostAndPort("127.0.0.1", socksPort), null, null))
|
socksProxyConfig = SocksProxyConfig(SocksProxyVersion.SOCKS5, NetworkHostAndPort("127.0.0.1", socksPort), null, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,6 +357,7 @@ class SocksTests {
|
|||||||
PEER_USER,
|
PEER_USER,
|
||||||
serverKeystore,
|
serverKeystore,
|
||||||
serverConfig.keyStorePassword,
|
serverConfig.keyStorePassword,
|
||||||
serverTruststore)
|
serverTruststore,
|
||||||
|
true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
|
|||||||
override val certificatesDirectory = Files.createTempDirectory("certs")
|
override val certificatesDirectory = Files.createTempDirectory("certs")
|
||||||
override val keyStorePassword: String get() = "cordacadevpass"
|
override val keyStorePassword: String get() = "cordacadevpass"
|
||||||
override val trustStorePassword: String get() = "trustpass"
|
override val trustStorePassword: String get() = "trustpass"
|
||||||
|
override val crlCheckSoftFail: Boolean = true
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val legalName = CordaX500Name("MegaCorp", "London", "GB")
|
val legalName = CordaX500Name("MegaCorp", "London", "GB")
|
||||||
|
@ -163,6 +163,7 @@ data class NodeConfigurationImpl(
|
|||||||
override val emailAddress: String,
|
override val emailAddress: String,
|
||||||
override val keyStorePassword: String,
|
override val keyStorePassword: String,
|
||||||
override val trustStorePassword: String,
|
override val trustStorePassword: String,
|
||||||
|
override val crlCheckSoftFail: Boolean,
|
||||||
override val dataSourceProperties: Properties,
|
override val dataSourceProperties: Properties,
|
||||||
override val compatibilityZoneURL: URL? = null,
|
override val compatibilityZoneURL: URL? = null,
|
||||||
override val rpcUsers: List<User>,
|
override val rpcUsers: List<User>,
|
||||||
@ -198,12 +199,12 @@ data class NodeConfigurationImpl(
|
|||||||
private val h2port: Int = 0,
|
private val h2port: Int = 0,
|
||||||
// do not use or remove (used by Capsule)
|
// do not use or remove (used by Capsule)
|
||||||
private val jarDirs: List<String> = emptyList()
|
private val jarDirs: List<String> = emptyList()
|
||||||
) : NodeConfiguration {
|
) : NodeConfiguration {
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = loggerFor<NodeConfigurationImpl>()
|
private val logger = loggerFor<NodeConfigurationImpl>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val rpcOptions: NodeRpcOptions = initialiseRpcOptions(rpcAddress, rpcSettings, SslOptions(baseDirectory / "certificates", keyStorePassword, trustStorePassword))
|
override val rpcOptions: NodeRpcOptions = initialiseRpcOptions(rpcAddress, rpcSettings, SslOptions(baseDirectory / "certificates", keyStorePassword, trustStorePassword, crlCheckSoftFail))
|
||||||
|
|
||||||
private fun initialiseRpcOptions(explicitAddress: NetworkHostAndPort?, settings: NodeRpcSettings, fallbackSslOptions: SSLConfiguration): NodeRpcOptions {
|
private fun initialiseRpcOptions(explicitAddress: NetworkHostAndPort?, settings: NodeRpcSettings, fallbackSslOptions: SSLConfiguration): NodeRpcOptions {
|
||||||
return when {
|
return when {
|
||||||
@ -384,8 +385,8 @@ data class SecurityConfiguration(val authService: SecurityConfiguration.AuthServ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyWithAdditionalUser(user: User) : DataSource{
|
fun copyWithAdditionalUser(user: User): DataSource {
|
||||||
val extendedList = this.users?.toMutableList()?: mutableListOf()
|
val extendedList = this.users?.toMutableList() ?: mutableListOf()
|
||||||
extendedList.add(user)
|
extendedList.add(user)
|
||||||
return DataSource(this.type, this.passwordEncryption, this.connection, listOf(*extendedList.toTypedArray()))
|
return DataSource(this.type, this.passwordEncryption, this.connection, listOf(*extendedList.toTypedArray()))
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,20 @@ import net.corda.nodeapi.internal.config.SSLConfiguration
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
|
|
||||||
data class SslOptions(override val certificatesDirectory: Path, override val keyStorePassword: String, override val trustStorePassword: String) : SSLConfiguration {
|
// TODO: we use both SSL and Ssl for names. We should pick one of them, or even better change to TLS
|
||||||
|
data class SslOptions(override val certificatesDirectory: Path,
|
||||||
|
override val keyStorePassword: String,
|
||||||
|
override val trustStorePassword: String,
|
||||||
|
override val crlCheckSoftFail: Boolean) : SSLConfiguration {
|
||||||
|
|
||||||
fun copy(certificatesDirectory: String = this.certificatesDirectory.toString(), keyStorePassword: String = this.keyStorePassword, trustStorePassword: String = this.trustStorePassword): SslOptions = copy(certificatesDirectory = certificatesDirectory.toAbsolutePath(), keyStorePassword = keyStorePassword, trustStorePassword = trustStorePassword)
|
fun copy(certificatesDirectory: String = this.certificatesDirectory.toString(),
|
||||||
|
keyStorePassword: String = this.keyStorePassword,
|
||||||
|
trustStorePassword: String = this.trustStorePassword,
|
||||||
|
crlCheckSoftFail: Boolean = this.crlCheckSoftFail): SslOptions = copy(
|
||||||
|
certificatesDirectory = certificatesDirectory.toAbsolutePath(),
|
||||||
|
keyStorePassword = keyStorePassword,
|
||||||
|
trustStorePassword = trustStorePassword,
|
||||||
|
crlCheckSoftFail = crlCheckSoftFail)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.toAbsolutePath() = Paths.get(this).toAbsolutePath()
|
private fun String.toAbsolutePath() = Paths.get(this).toAbsolutePath()
|
@ -4,7 +4,6 @@ import net.corda.core.internal.div
|
|||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.node.services.Permissions
|
import net.corda.node.services.Permissions
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.config.shouldInitCrashShell
|
|
||||||
import net.corda.nodeapi.internal.config.User
|
import net.corda.nodeapi.internal.config.User
|
||||||
import net.corda.tools.shell.ShellConfiguration
|
import net.corda.tools.shell.ShellConfiguration
|
||||||
import net.corda.tools.shell.ShellConfiguration.Companion.COMMANDS_DIR
|
import net.corda.tools.shell.ShellConfiguration.Companion.COMMANDS_DIR
|
||||||
@ -22,7 +21,8 @@ fun NodeConfiguration.toShellConfig(): ShellConfiguration {
|
|||||||
ShellSslOptions(sslKeystore,
|
ShellSslOptions(sslKeystore,
|
||||||
keyStorePassword,
|
keyStorePassword,
|
||||||
trustStoreFile,
|
trustStoreFile,
|
||||||
trustStorePassword)
|
trustStorePassword,
|
||||||
|
crlCheckSoftFail)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
@ -11,6 +11,7 @@ myLegalName = "Vast Global MegaCorp, Ltd"
|
|||||||
emailAddress = "admin@company.com"
|
emailAddress = "admin@company.com"
|
||||||
keyStorePassword = "cordacadevpass"
|
keyStorePassword = "cordacadevpass"
|
||||||
trustStorePassword = "trustpass"
|
trustStorePassword = "trustpass"
|
||||||
|
crlCheckSoftFail = true
|
||||||
dataSourceProperties = {
|
dataSourceProperties = {
|
||||||
dataSourceClassName = org.h2.jdbcx.JdbcDataSource
|
dataSourceClassName = org.h2.jdbcx.JdbcDataSource
|
||||||
dataSource.url = "jdbc:h2:file:"${baseDirectory}"/persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT="${h2port}
|
dataSource.url = "jdbc:h2:file:"${baseDirectory}"/persistence;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=0;AUTO_SERVER_PORT="${h2port}
|
||||||
|
@ -103,7 +103,7 @@ class NodeConfigurationImplTest {
|
|||||||
adminAddress = NetworkHostAndPort("localhost", 2),
|
adminAddress = NetworkHostAndPort("localhost", 2),
|
||||||
standAloneBroker = false,
|
standAloneBroker = false,
|
||||||
useSsl = false,
|
useSsl = false,
|
||||||
ssl = SslOptions(baseDirectory / "certificates", keyStorePassword, trustStorePassword))
|
ssl = SslOptions(baseDirectory / "certificates", keyStorePassword, trustStorePassword, true))
|
||||||
return NodeConfigurationImpl(
|
return NodeConfigurationImpl(
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
myLegalName = ALICE_NAME,
|
myLegalName = ALICE_NAME,
|
||||||
@ -122,7 +122,8 @@ class NodeConfigurationImplTest {
|
|||||||
noLocalShell = false,
|
noLocalShell = false,
|
||||||
rpcSettings = rpcSettings,
|
rpcSettings = rpcSettings,
|
||||||
relay = null,
|
relay = null,
|
||||||
enterpriseConfiguration = EnterpriseConfiguration((MutualExclusionConfiguration(false, "", 20000, 40000)))
|
enterpriseConfiguration = EnterpriseConfiguration((MutualExclusionConfiguration(false, "", 20000, 40000))),
|
||||||
|
crlCheckSoftFail = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,9 +86,13 @@ class KeyStores(val keyStore: UnsafeKeyStore, val trustStore: UnsafeKeyStore) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data class TestSslOptions(override val certificatesDirectory: Path, override val keyStorePassword: String, override val trustStorePassword: String) : SSLConfiguration
|
|
||||||
|
|
||||||
private fun sslConfiguration(directory: Path) = TestSslOptions(directory, keyStore.password, trustStore.password)
|
data class TestSslOptions(override val certificatesDirectory: Path,
|
||||||
|
override val keyStorePassword: String,
|
||||||
|
override val trustStorePassword: String,
|
||||||
|
override val crlCheckSoftFail: Boolean) : SSLConfiguration
|
||||||
|
|
||||||
|
private fun sslConfiguration(directory: Path) = TestSslOptions(directory, keyStore.password, trustStore.password, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AutoClosableSSLConfiguration : AutoCloseable {
|
interface AutoClosableSSLConfiguration : AutoCloseable {
|
||||||
@ -131,6 +135,7 @@ data class UnsafeKeyStore(private val delegate: KeyStore, val password: String)
|
|||||||
|
|
||||||
class TemporaryFile(fileName: String, val directory: Path) : AutoCloseable {
|
class TemporaryFile(fileName: String, val directory: Path) : AutoCloseable {
|
||||||
val file: Path = (directory / fileName).createFile().toAbsolutePath()
|
val file: Path = (directory / fileName).createFile().toAbsolutePath()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
file.toFile().deleteOnExit()
|
file.toFile().deleteOnExit()
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ fun configureTestSSL(legalName: CordaX500Name): SSLConfiguration {
|
|||||||
override val certificatesDirectory = Files.createTempDirectory("certs")
|
override val certificatesDirectory = Files.createTempDirectory("certs")
|
||||||
override val keyStorePassword: String get() = "cordacadevpass"
|
override val keyStorePassword: String get() = "cordacadevpass"
|
||||||
override val trustStorePassword: String get() = "trustpass"
|
override val trustStorePassword: String get() = "trustpass"
|
||||||
|
override val crlCheckSoftFail: Boolean = true
|
||||||
|
|
||||||
init {
|
init {
|
||||||
configureDevKeyAndTrustStores(legalName)
|
configureDevKeyAndTrustStores(legalName)
|
||||||
@ -130,22 +131,24 @@ fun createDevNodeCaCertPath(
|
|||||||
/** Application of [doAnswer] that gets a value from the given [map] using the arg at [argIndex] as key. */
|
/** Application of [doAnswer] that gets a value from the given [map] using the arg at [argIndex] as key. */
|
||||||
fun doLookup(map: Map<*, *>, argIndex: Int = 0) = doAnswer { map[it.arguments[argIndex]] }
|
fun doLookup(map: Map<*, *>, argIndex: Int = 0) = doAnswer { map[it.arguments[argIndex]] }
|
||||||
|
|
||||||
fun SSLConfiguration.useSslRpcOverrides(): Map<String, String> {
|
fun SSLConfiguration.useSslRpcOverrides(): Map<String, Any> {
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"rpcSettings.useSsl" to "true",
|
"rpcSettings.useSsl" to "true",
|
||||||
"rpcSettings.ssl.certificatesDirectory" to certificatesDirectory.toString(),
|
"rpcSettings.ssl.certificatesDirectory" to certificatesDirectory.toString(),
|
||||||
"rpcSettings.ssl.keyStorePassword" to keyStorePassword,
|
"rpcSettings.ssl.keyStorePassword" to keyStorePassword,
|
||||||
"rpcSettings.ssl.trustStorePassword" to trustStorePassword
|
"rpcSettings.ssl.trustStorePassword" to trustStorePassword,
|
||||||
|
"rpcSettings.ssl.crlCheckSoftFail" to true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SSLConfiguration.noSslRpcOverrides(rpcAdminAddress: NetworkHostAndPort): Map<String, String> {
|
fun SSLConfiguration.noSslRpcOverrides(rpcAdminAddress: NetworkHostAndPort): Map<String, Any> {
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"rpcSettings.adminAddress" to rpcAdminAddress.toString(),
|
"rpcSettings.adminAddress" to rpcAdminAddress.toString(),
|
||||||
"rpcSettings.useSsl" to "false",
|
"rpcSettings.useSsl" to "false",
|
||||||
"rpcSettings.ssl.certificatesDirectory" to certificatesDirectory.toString(),
|
"rpcSettings.ssl.certificatesDirectory" to certificatesDirectory.toString(),
|
||||||
"rpcSettings.ssl.keyStorePassword" to keyStorePassword,
|
"rpcSettings.ssl.keyStorePassword" to keyStorePassword,
|
||||||
"rpcSettings.ssl.trustStorePassword" to trustStorePassword
|
"rpcSettings.ssl.trustStorePassword" to trustStorePassword,
|
||||||
|
"rpcSettings.ssl.crlCheckSoftFail" to true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
|
|||||||
startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
|
startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
|
||||||
|
|
||||||
val sslConfiguration = ShellSslOptions(clientSslOptions.sslKeystore, clientSslOptions.keyStorePassword,
|
val sslConfiguration = ShellSslOptions(clientSslOptions.sslKeystore, clientSslOptions.keyStorePassword,
|
||||||
clientSslOptions.trustStoreFile, clientSslOptions.trustStorePassword)
|
clientSslOptions.trustStoreFile, clientSslOptions.trustStorePassword, clientSslOptions.crlCheckSoftFail)
|
||||||
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
|
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
|
||||||
user = user.username, password = user.password,
|
user = user.username, password = user.password,
|
||||||
hostAndPort = node.rpcAddress,
|
hostAndPort = node.rpcAddress,
|
||||||
@ -140,7 +140,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
|
|||||||
startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
|
startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
|
||||||
|
|
||||||
val sslConfiguration = ShellSslOptions(clientSslOptions.sslKeystore, clientSslOptions.keyStorePassword,
|
val sslConfiguration = ShellSslOptions(clientSslOptions.sslKeystore, clientSslOptions.keyStorePassword,
|
||||||
clientSslOptions.trustStoreFile, clientSslOptions.trustStorePassword)
|
clientSslOptions.trustStoreFile, clientSslOptions.trustStorePassword, clientSslOptions.crlCheckSoftFail)
|
||||||
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
|
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
|
||||||
user = user.username, password = user.password,
|
user = user.username, password = user.password,
|
||||||
hostAndPort = node.rpcAddress,
|
hostAndPort = node.rpcAddress,
|
||||||
@ -222,7 +222,7 @@ class InteractiveShellIntegrationTest : IntegrationTest() {
|
|||||||
startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
|
startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
|
||||||
|
|
||||||
val sslConfiguration = ShellSslOptions(clientSslOptions.sslKeystore, clientSslOptions.keyStorePassword,
|
val sslConfiguration = ShellSslOptions(clientSslOptions.sslKeystore, clientSslOptions.keyStorePassword,
|
||||||
clientSslOptions.trustStoreFile, clientSslOptions.trustStorePassword)
|
clientSslOptions.trustStoreFile, clientSslOptions.trustStorePassword, clientSslOptions.crlCheckSoftFail)
|
||||||
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
|
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
|
||||||
user = user.username, password = user.password,
|
user = user.username, password = user.password,
|
||||||
hostAndPort = node.rpcAddress,
|
hostAndPort = node.rpcAddress,
|
||||||
|
@ -23,6 +23,12 @@ data class ShellConfiguration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ShellSslOptions(override val sslKeystore: Path, override val keyStorePassword: String, override val trustStoreFile:Path, override val trustStorePassword: String) : SSLConfiguration {
|
//TODO: sslKeystore -> it's a path not the keystore itself.
|
||||||
|
//TODO: trustStoreFile -> it's a path not the file itself.
|
||||||
|
data class ShellSslOptions(override val sslKeystore: Path,
|
||||||
|
override val keyStorePassword: String,
|
||||||
|
override val trustStoreFile: Path,
|
||||||
|
override val trustStorePassword: String,
|
||||||
|
override val crlCheckSoftFail: Boolean) : SSLConfiguration {
|
||||||
override val certificatesDirectory: Path get() = Paths.get("")
|
override val certificatesDirectory: Path get() = Paths.get("")
|
||||||
}
|
}
|
@ -37,10 +37,10 @@ class CommandLineOptionParser {
|
|||||||
.accepts("commands-directory", "The directory with additional CrAsH shell commands.")
|
.accepts("commands-directory", "The directory with additional CrAsH shell commands.")
|
||||||
.withOptionalArg()
|
.withOptionalArg()
|
||||||
private val hostArg = optionParser
|
private val hostArg = optionParser
|
||||||
.acceptsAll(listOf("h","host"), "The host of the Corda node.")
|
.acceptsAll(listOf("h", "host"), "The host of the Corda node.")
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
private val portArg = optionParser
|
private val portArg = optionParser
|
||||||
.acceptsAll(listOf("p","port"), "The port of the Corda node.")
|
.acceptsAll(listOf("p", "port"), "The port of the Corda node.")
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
private val userArg = optionParser
|
private val userArg = optionParser
|
||||||
.accepts("user", "The RPC user name.")
|
.accepts("user", "The RPC user name.")
|
||||||
@ -219,11 +219,13 @@ private class ShellConfigurationFile {
|
|||||||
sslKeystore = Paths.get(it.keystore.path),
|
sslKeystore = Paths.get(it.keystore.path),
|
||||||
keyStorePassword = it.keystore.password,
|
keyStorePassword = it.keystore.password,
|
||||||
trustStoreFile = Paths.get(it.truststore.path),
|
trustStoreFile = Paths.get(it.truststore.path),
|
||||||
trustStorePassword = it.truststore.password)
|
trustStorePassword = it.truststore.password,
|
||||||
|
crlCheckSoftFail = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ShellConfiguration(
|
return ShellConfiguration(
|
||||||
commandsDirectory = extensions?.commands?.let { Paths.get(it.path) } ?: Paths.get(".") / COMMANDS_DIR,
|
commandsDirectory = extensions?.commands?.let { Paths.get(it.path) } ?: Paths.get(".")
|
||||||
|
/ COMMANDS_DIR,
|
||||||
cordappsDirectory = extensions?.cordapps?.let { Paths.get(it.path) },
|
cordappsDirectory = extensions?.cordapps?.let { Paths.get(it.path) },
|
||||||
user = node.user ?: "",
|
user = node.user ?: "",
|
||||||
password = node.password ?: "",
|
password = node.password ?: "",
|
||||||
|
@ -112,12 +112,13 @@ class StandaloneShellArgsParserTest {
|
|||||||
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
||||||
keyStoreType = "dummy",
|
keyStoreType = "dummy",
|
||||||
trustStoreType = "dummy"
|
trustStoreType = "dummy"
|
||||||
)
|
)
|
||||||
|
|
||||||
val expectedSsl = ShellSslOptions(sslKeystore = Paths.get("/x/y/keystore.jks"),
|
val expectedSsl = ShellSslOptions(sslKeystore = Paths.get("/x/y/keystore.jks"),
|
||||||
keyStorePassword = "pass1",
|
keyStorePassword = "pass1",
|
||||||
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
||||||
trustStorePassword = "pass2")
|
trustStorePassword = "pass2",
|
||||||
|
crlCheckSoftFail = true)
|
||||||
val expectedConfig = ShellConfiguration(
|
val expectedConfig = ShellConfiguration(
|
||||||
commandsDirectory = Paths.get("/x/y/commands"),
|
commandsDirectory = Paths.get("/x/y/commands"),
|
||||||
cordappsDirectory = Paths.get("/x/y/cordapps"),
|
cordappsDirectory = Paths.get("/x/y/cordapps"),
|
||||||
@ -158,7 +159,8 @@ class StandaloneShellArgsParserTest {
|
|||||||
val expectedSsl = ShellSslOptions(sslKeystore = Paths.get("/x/y/keystore.jks"),
|
val expectedSsl = ShellSslOptions(sslKeystore = Paths.get("/x/y/keystore.jks"),
|
||||||
keyStorePassword = "pass1",
|
keyStorePassword = "pass1",
|
||||||
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
||||||
trustStorePassword = "pass2")
|
trustStorePassword = "pass2",
|
||||||
|
crlCheckSoftFail = true)
|
||||||
val expectedConfig = ShellConfiguration(
|
val expectedConfig = ShellConfiguration(
|
||||||
commandsDirectory = Paths.get("/x/y/commands"),
|
commandsDirectory = Paths.get("/x/y/commands"),
|
||||||
cordappsDirectory = Paths.get("/x/y/cordapps"),
|
cordappsDirectory = Paths.get("/x/y/cordapps"),
|
||||||
@ -197,7 +199,8 @@ class StandaloneShellArgsParserTest {
|
|||||||
val expectedSsl = ShellSslOptions(sslKeystore = Paths.get("/x/y/cmd.jks"),
|
val expectedSsl = ShellSslOptions(sslKeystore = Paths.get("/x/y/cmd.jks"),
|
||||||
keyStorePassword = "pass1",
|
keyStorePassword = "pass1",
|
||||||
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
trustStoreFile = Paths.get("/x/y/truststore.jks"),
|
||||||
trustStorePassword = "pass2")
|
trustStorePassword = "pass2",
|
||||||
|
crlCheckSoftFail = true)
|
||||||
val expectedConfig = ShellConfiguration(
|
val expectedConfig = ShellConfiguration(
|
||||||
commandsDirectory = Paths.get("/x/y/commands"),
|
commandsDirectory = Paths.get("/x/y/commands"),
|
||||||
cordappsDirectory = Paths.get("/x/y/cordapps"),
|
cordappsDirectory = Paths.get("/x/y/cordapps"),
|
||||||
|
@ -24,6 +24,7 @@ import java.nio.file.Path
|
|||||||
class WebServerConfig(override val baseDirectory: Path, val config: Config) : NodeSSLConfiguration {
|
class WebServerConfig(override val baseDirectory: Path, val config: Config) : NodeSSLConfiguration {
|
||||||
override val keyStorePassword: String by config
|
override val keyStorePassword: String by config
|
||||||
override val trustStorePassword: String by config
|
override val trustStorePassword: String by config
|
||||||
|
override val crlCheckSoftFail: Boolean by config
|
||||||
val useHTTPS: Boolean by config
|
val useHTTPS: Boolean by config
|
||||||
val myLegalName: String by config
|
val myLegalName: String by config
|
||||||
val rpcAddress: NetworkHostAndPort by lazy {
|
val rpcAddress: NetworkHostAndPort by lazy {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user