Merge pull request #666 from corda/mnesbit-custom-bridge-ssl-config

Fix the custom ssl configuration logic on the bridge
This commit is contained in:
Matthew Nesbit 2018-04-03 13:52:53 +01:00 committed by GitHub
commit d0cec8cabb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 158 additions and 24 deletions

View File

@ -38,6 +38,14 @@ enum class BridgeMode {
FloatOuter
}
interface BridgeSSLConfiguration : SSLConfiguration {
override val keyStorePassword: String
override val trustStorePassword: String
override val sslKeystore: Path
override val trustStoreFile: Path
}
/**
* Details of the local Artemis broker.
* Required in SenderReceiver and FloatInner modes.
@ -45,7 +53,7 @@ enum class BridgeMode {
interface BridgeOutboundConfiguration {
val artemisBrokerAddress: NetworkHostAndPort
// Allows override of [KeyStore] details for the artemis connection, otherwise the general top level details are used.
val customSSLConfiguration: SSLConfiguration?
val customSSLConfiguration: BridgeSSLConfiguration?
// Allows use of a SOCKS 4/5 proxy
val socksProxyConfig: SocksProxyConfig?
}
@ -58,7 +66,7 @@ interface BridgeOutboundConfiguration {
interface BridgeInboundConfiguration {
val listeningAddress: NetworkHostAndPort
// Allows override of [KeyStore] details for the AMQP listener port, otherwise the general top level details are used.
val customSSLConfiguration: SSLConfiguration?
val customSSLConfiguration: BridgeSSLConfiguration?
}
/**
@ -70,9 +78,9 @@ interface FloatInnerConfiguration {
val expectedCertificateSubject: CordaX500Name
// Allows override of [KeyStore] details for the control port, otherwise the general top level details are used.
// Used for connection to Float in DMZ
val customSSLConfiguration: SSLConfiguration?
val customSSLConfiguration: BridgeSSLConfiguration?
// The SSL keystores to provision into the Float in DMZ
val customFloatOuterSSLConfiguration: SSLConfiguration?
val customFloatOuterSSLConfiguration: BridgeSSLConfiguration?
}
/**
@ -83,7 +91,7 @@ interface FloatOuterConfiguration {
val floatAddress: NetworkHostAndPort
val expectedCertificateSubject: CordaX500Name
// Allows override of [KeyStore] details for the control port, otherwise the general top level details are used.
val customSSLConfiguration: SSLConfiguration?
val customSSLConfiguration: BridgeSSLConfiguration?
}
interface BridgeConfiguration : NodeSSLConfiguration {

View File

@ -10,10 +10,8 @@
package net.corda.bridge.services.artemis
import net.corda.bridge.services.api.BridgeArtemisConnectionService
import net.corda.bridge.services.api.BridgeAuditService
import net.corda.bridge.services.api.BridgeConfiguration
import net.corda.bridge.services.api.ServiceStateSupport
import net.corda.bridge.services.api.*
import net.corda.bridge.services.config.BridgeSSLConfigurationImpl
import net.corda.bridge.services.util.ServiceStateCombiner
import net.corda.bridge.services.util.ServiceStateHelper
import net.corda.core.internal.ThreadBox
@ -23,7 +21,6 @@ import net.corda.nodeapi.ArtemisTcpTransport
import net.corda.nodeapi.ConnectionDirection
import net.corda.nodeapi.internal.ArtemisMessagingClient
import net.corda.nodeapi.internal.ArtemisMessagingComponent
import net.corda.nodeapi.internal.config.SSLConfiguration
import org.apache.activemq.artemis.api.core.client.ActiveMQClient
import org.apache.activemq.artemis.api.core.client.FailoverEventType
import org.apache.activemq.artemis.api.core.client.ServerLocator
@ -46,13 +43,13 @@ class BridgeArtemisConnectionServiceImpl(val conf: BridgeConfiguration,
}
private val state = ThreadBox(InnerState())
private val sslConfiguration: SSLConfiguration
private val sslConfiguration: BridgeSSLConfiguration
private val statusFollower: ServiceStateCombiner
private var statusSubscriber: Subscription? = null
init {
statusFollower = ServiceStateCombiner(listOf(auditService))
sslConfiguration = conf.outboundConfig?.customSSLConfiguration ?: conf
sslConfiguration = conf.outboundConfig?.customSSLConfiguration ?: BridgeSSLConfigurationImpl(conf)
}
override fun start() {

View File

@ -13,38 +13,47 @@ package net.corda.bridge.services.config
import com.typesafe.config.Config
import net.corda.bridge.services.api.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.ArtemisMessagingComponent
import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.nodeapi.internal.config.NodeSSLConfiguration
import net.corda.nodeapi.internal.config.parseAs
import net.corda.nodeapi.internal.protonwrapper.netty.SocksProxyConfig
import java.nio.file.Path
import java.nio.file.Paths
fun Config.parseAsBridgeConfiguration(): BridgeConfiguration = parseAs<BridgeConfigurationImpl>()
data class CustomSSLConfiguration(override val keyStorePassword: String,
override val trustStorePassword: String,
override val certificatesDirectory: Path) : SSLConfiguration
data class BridgeSSLConfigurationImpl(override val keyStorePassword: String,
override val trustStorePassword: String,
override val certificatesDirectory: Path = Paths.get("certificates"),
override val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
override val trustStoreFile: Path = certificatesDirectory / "truststore.jks") : BridgeSSLConfiguration {
constructor(config: NodeSSLConfiguration) : this(config.keyStorePassword, config.trustStorePassword, config.certificatesDirectory, config.sslKeystore, config.trustStoreFile)
}
data class BridgeOutboundConfigurationImpl(override val artemisBrokerAddress: NetworkHostAndPort,
override val customSSLConfiguration: CustomSSLConfiguration?,
override val customSSLConfiguration: BridgeSSLConfigurationImpl?,
override val socksProxyConfig: SocksProxyConfig? = null) : BridgeOutboundConfiguration
data class BridgeInboundConfigurationImpl(override val listeningAddress: NetworkHostAndPort,
override val customSSLConfiguration: CustomSSLConfiguration?) : BridgeInboundConfiguration
override val customSSLConfiguration: BridgeSSLConfigurationImpl?) : BridgeInboundConfiguration
data class FloatInnerConfigurationImpl(override val floatAddresses: List<NetworkHostAndPort>,
override val expectedCertificateSubject: CordaX500Name,
override val customSSLConfiguration: CustomSSLConfiguration?,
override val customFloatOuterSSLConfiguration: CustomSSLConfiguration?) : FloatInnerConfiguration
override val customSSLConfiguration: BridgeSSLConfigurationImpl?,
override val customFloatOuterSSLConfiguration: BridgeSSLConfigurationImpl?) : FloatInnerConfiguration
data class FloatOuterConfigurationImpl(override val floatAddress: NetworkHostAndPort,
override val expectedCertificateSubject: CordaX500Name,
override val customSSLConfiguration: CustomSSLConfiguration?) : FloatOuterConfiguration
override val customSSLConfiguration: BridgeSSLConfigurationImpl?) : FloatOuterConfiguration
data class BridgeConfigurationImpl(
override val baseDirectory: Path,
override val certificatesDirectory: Path = baseDirectory / "certificates",
override val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
override val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
override val keyStorePassword: String,
override val trustStorePassword: String,
override val bridgeMode: BridgeMode,

View File

@ -11,6 +11,7 @@
package net.corda.bridge.services.receiver
import net.corda.bridge.services.api.*
import net.corda.bridge.services.config.BridgeSSLConfigurationImpl
import net.corda.bridge.services.receiver.FloatControlTopics.FLOAT_DATA_TOPIC
import net.corda.bridge.services.util.ServiceStateCombiner
import net.corda.bridge.services.util.ServiceStateHelper
@ -21,7 +22,6 @@ import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2P_PREFIX
import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus
import net.corda.nodeapi.internal.protonwrapper.messages.ReceivedMessage
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer
@ -47,7 +47,7 @@ class FloatControlListenerService(val conf: BridgeConfiguration,
private var connectSubscriber: Subscription? = null
private var receiveSubscriber: Subscription? = null
private var amqpControlServer: AMQPServer? = null
private val sslConfiguration: SSLConfiguration
private val sslConfiguration: BridgeSSLConfiguration
private val keyStore: KeyStore
private val keyStorePrivateKeyPassword: String
private val trustStore: KeyStore
@ -59,7 +59,7 @@ class FloatControlListenerService(val conf: BridgeConfiguration,
init {
statusFollower = ServiceStateCombiner(listOf(auditService, amqpListener))
sslConfiguration = conf.floatOuterConfig?.customSSLConfiguration ?: conf
sslConfiguration = conf.floatOuterConfig?.customSSLConfiguration ?: BridgeSSLConfigurationImpl(conf)
keyStore = sslConfiguration.loadSslKeyStore().internal
keyStorePrivateKeyPassword = sslConfiguration.keyStorePassword
trustStore = sslConfiguration.loadTrustStore().internal

View File

@ -19,6 +19,7 @@ import org.junit.Assert.assertNull
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.nio.file.Paths
class ConfigTest {
@Rule
@ -63,4 +64,44 @@ class ConfigTest {
assertEquals(NetworkHostAndPort("localhost", 12005), config.floatOuterConfig!!.floatAddress)
assertEquals(CordaX500Name.parse("O=Bank A, L=London, C=GB"), config.floatOuterConfig!!.expectedCertificateSubject)
}
@Test
fun `Load overridden cert config`() {
val configResource = "/net/corda/bridge/custombasecerts/bridge.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
assertEquals(Paths.get("customcerts/mysslkeystore.jks"), config.sslKeystore)
assertEquals(Paths.get("customcerts/mytruststore.jks"), config.trustStoreFile)
}
@Test
fun `Load custom inner certificate config`() {
val configResource = "/net/corda/bridge/separatedwithcustomcerts/bridge/bridge.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
assertEquals(Paths.get("outboundcerts/outboundkeys.jks"), config.outboundConfig!!.customSSLConfiguration!!.sslKeystore)
assertEquals(Paths.get("outboundcerts/outboundtrust.jks"), config.outboundConfig!!.customSSLConfiguration!!.trustStoreFile)
assertEquals("outboundkeypassword", config.outboundConfig!!.customSSLConfiguration!!.keyStorePassword)
assertEquals("outboundtrustpassword", config.outboundConfig!!.customSSLConfiguration!!.trustStorePassword)
assertNull(config.inboundConfig)
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), config.floatInnerConfig!!.customSSLConfiguration!!.sslKeystore)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), config.floatInnerConfig!!.customSSLConfiguration!!.trustStoreFile)
assertEquals("tunnelkeypassword", config.floatInnerConfig!!.customSSLConfiguration!!.keyStorePassword)
assertEquals("tunneltrustpassword", config.floatInnerConfig!!.customSSLConfiguration!!.trustStorePassword)
assertNull(config.floatOuterConfig)
}
@Test
fun `Load custom outer certificate config`() {
val configResource = "/net/corda/bridge/separatedwithcustomcerts/float/bridge.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
assertEquals(Paths.get("inboundcerts/inboundkeys.jks"), config.inboundConfig!!.customSSLConfiguration!!.sslKeystore)
assertEquals(Paths.get("inboundcerts/inboundtrust.jks"), config.inboundConfig!!.customSSLConfiguration!!.trustStoreFile)
assertEquals("inboundkeypassword", config.inboundConfig!!.customSSLConfiguration!!.keyStorePassword)
assertEquals("inboundtrustpassword", config.inboundConfig!!.customSSLConfiguration!!.trustStorePassword)
assertNull(config.outboundConfig)
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), config.floatOuterConfig!!.customSSLConfiguration!!.sslKeystore)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), config.floatOuterConfig!!.customSSLConfiguration!!.trustStoreFile)
assertEquals("tunnelkeypassword", config.floatOuterConfig!!.customSSLConfiguration!!.keyStorePassword)
assertEquals("tunneltrustpassword", config.floatOuterConfig!!.customSSLConfiguration!!.trustStorePassword)
assertNull(config.floatInnerConfig)
}
}

View File

@ -0,0 +1,19 @@
//
// R3 Proprietary and Confidential
//
// Copyright (c) 2018 R3 Limited. All rights reserved.
//
// The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
//
// Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
bridgeMode = SenderReceiver
sslKeystore = "customcerts/mysslkeystore.jks"
trustStoreFile = "customcerts/mytruststore.jks"
outboundConfig : {
artemisBrokerAddress = "localhost:11005"
}
inboundConfig : {
listeningAddress = "0.0.0.0:10005"
}
networkParametersPath = network-parameters

View File

@ -0,0 +1,30 @@
//
// R3 Proprietary and Confidential
//
// Copyright (c) 2018 R3 Limited. All rights reserved.
//
// The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
//
// Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
bridgeMode = FloatInner
outboundConfig : {
artemisBrokerAddress = "localhost:11005"
customSSLConfiguration : {
keyStorePassword = "outboundkeypassword"
trustStorePassword = "outboundtrustpassword"
sslKeystore = "outboundcerts/outboundkeys.jks"
trustStoreFile = "outboundcerts/outboundtrust.jks"
}
}
floatInnerConfig : {
floatAddresses = [ "localhost:12005" ]
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
keyStorePassword = "tunnelkeypassword"
trustStorePassword = "tunneltrustpassword"
sslKeystore = "tunnelcerts/tunnelkeys.jks"
trustStoreFile = "tunnelcerts/tunneltrust.jks"
}
}
networkParametersPath = network-parameters

View File

@ -0,0 +1,30 @@
//
// R3 Proprietary and Confidential
//
// Copyright (c) 2018 R3 Limited. All rights reserved.
//
// The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
//
// Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
bridgeMode = FloatOuter
inboundConfig : {
listeningAddress = "0.0.0.0:10005"
customSSLConfiguration : {
keyStorePassword = "inboundkeypassword"
trustStorePassword = "inboundtrustpassword"
sslKeystore = "inboundcerts/inboundkeys.jks"
trustStoreFile = "inboundcerts/inboundtrust.jks"
}
}
floatOuterConfig : {
floatAddress = "localhost:12005"
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
keyStorePassword = "tunnelkeypassword"
trustStorePassword = "tunneltrustpassword"
sslKeystore = "tunnelcerts/tunnelkeys.jks"
trustStoreFile = "tunnelcerts/tunneltrust.jks"
}
}
networkParametersPath = network-parameters