Some code tidy up ahead of post-GA development. (#3500)

Handle SSL Handshake timeouts properly
This commit is contained in:
Matthew Nesbit 2018-07-03 14:16:31 +01:00 committed by GitHub
parent a5f43110f0
commit d0568121b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 200 additions and 135 deletions

View File

@ -11,13 +11,13 @@ import net.corda.nodeapi.internal.ArtemisMessagingClient
import net.corda.nodeapi.internal.ArtemisMessagingComponent import net.corda.nodeapi.internal.ArtemisMessagingComponent
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_P2P_USER import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NODE_P2P_USER
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2PMessagingHeaders import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2PMessagingHeaders
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.PEER_USER
import net.corda.nodeapi.internal.ArtemisMessagingComponent.RemoteInboxAddress.Companion.translateLocalQueueToInboxAddress import net.corda.nodeapi.internal.ArtemisMessagingComponent.RemoteInboxAddress.Companion.translateLocalQueueToInboxAddress
import net.corda.nodeapi.internal.ArtemisSessionProvider import net.corda.nodeapi.internal.ArtemisSessionProvider
import net.corda.nodeapi.internal.bridging.AMQPBridgeManager.AMQPBridge.Companion.getBridgeName import net.corda.nodeapi.internal.bridging.AMQPBridgeManager.AMQPBridge.Companion.getBridgeName
import net.corda.nodeapi.internal.config.NodeSSLConfiguration import net.corda.nodeapi.internal.config.NodeSSLConfiguration
import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration
import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.SimpleString
import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE
import org.apache.activemq.artemis.api.core.client.ClientConsumer import org.apache.activemq.artemis.api.core.client.ClientConsumer
@ -37,16 +37,24 @@ import kotlin.concurrent.withLock
* The Netty thread pool used by the AMQPBridges is also shared and managed by the AMQPBridgeManager. * The Netty thread pool used by the AMQPBridges is also shared and managed by the AMQPBridgeManager.
*/ */
@VisibleForTesting @VisibleForTesting
class AMQPBridgeManager(config: NodeSSLConfiguration, private val maxMessageSize: Int, private val artemisMessageClientFactory: () -> ArtemisSessionProvider) : BridgeManager { class AMQPBridgeManager(config: NodeSSLConfiguration, maxMessageSize: Int, private val artemisMessageClientFactory: () -> ArtemisSessionProvider) : BridgeManager {
private val lock = ReentrantLock() private val lock = ReentrantLock()
private val bridgeNameToBridgeMap = mutableMapOf<String, AMQPBridge>() private val bridgeNameToBridgeMap = mutableMapOf<String, AMQPBridge>()
private class AMQPConfigurationImpl private constructor(override val keyStore: KeyStore,
override val keyStorePrivateKeyPassword: CharArray,
override val trustStore: KeyStore,
override val maxMessageSize: Int) : AMQPConfiguration {
constructor(config: NodeSSLConfiguration, maxMessageSize: Int) : this(config.loadSslKeyStore().internal,
config.keyStorePassword.toCharArray(),
config.loadTrustStore().internal,
maxMessageSize)
}
private val amqpConfig: AMQPConfiguration = AMQPConfigurationImpl(config, maxMessageSize)
private var sharedEventLoopGroup: EventLoopGroup? = null private var sharedEventLoopGroup: EventLoopGroup? = null
private val keyStore = config.loadSslKeyStore().internal
private val keyStorePrivateKeyPassword: String = config.keyStorePassword
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) : this(config, maxMessageSize, { ArtemisMessagingClient(config, p2pAddress, maxMessageSize) }) constructor(config: NodeSSLConfiguration, p2pAddress: NetworkHostAndPort, maxMessageSize: Int) : this(config, maxMessageSize, { ArtemisMessagingClient(config, p2pAddress, maxMessageSize) })
@ -65,26 +73,26 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val maxMessageSize
private class AMQPBridge(private val queueName: String, private class AMQPBridge(private val queueName: String,
private val target: NetworkHostAndPort, private val target: NetworkHostAndPort,
private val legalNames: Set<CordaX500Name>, private val legalNames: Set<CordaX500Name>,
keyStore: KeyStore, private val amqpConfig: AMQPConfiguration,
keyStorePrivateKeyPassword: String,
trustStore: KeyStore,
crlCheckSoftFail: Boolean,
sharedEventGroup: EventLoopGroup, sharedEventGroup: EventLoopGroup,
private val artemis: ArtemisSessionProvider, private val artemis: ArtemisSessionProvider) {
private val maxMessageSize: Int) {
companion object { companion object {
fun getBridgeName(queueName: String, hostAndPort: NetworkHostAndPort): String = "$queueName -> $hostAndPort" fun getBridgeName(queueName: String, hostAndPort: NetworkHostAndPort): String = "$queueName -> $hostAndPort"
private val log = contextLogger() private val log = contextLogger()
} }
private fun withMDC(block: () -> Unit) { private fun withMDC(block: () -> Unit) {
MDC.put("queueName", queueName) val oldMDC = MDC.getCopyOfContextMap()
MDC.put("target", target.toString()) try {
MDC.put("bridgeName", bridgeName) MDC.put("queueName", queueName)
MDC.put("legalNames", legalNames.joinToString(separator = ";") { it.toString() }) MDC.put("target", target.toString())
MDC.put("maxMessageSize", maxMessageSize.toString()) MDC.put("bridgeName", bridgeName)
block() MDC.put("legalNames", legalNames.joinToString(separator = ";") { it.toString() })
MDC.clear() MDC.put("maxMessageSize", amqpConfig.maxMessageSize.toString())
block()
} finally {
MDC.setContextMap(oldMDC)
}
} }
private fun logDebugWithMDC(msg: () -> String) { private fun logDebugWithMDC(msg: () -> String) {
@ -97,7 +105,7 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val maxMessageSize
private fun logWarnWithMDC(msg: String) = withMDC { log.warn(msg) } private fun logWarnWithMDC(msg: String) = withMDC { log.warn(msg) }
val amqpClient = AMQPClient(listOf(target), legalNames, PEER_USER, PEER_USER, keyStore, keyStorePrivateKeyPassword, trustStore, crlCheckSoftFail, sharedThreadPool = sharedEventGroup, maxMessageSize = maxMessageSize) val amqpClient = AMQPClient(listOf(target), legalNames, amqpConfig, sharedThreadPool = sharedEventGroup)
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
@ -149,8 +157,8 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val maxMessageSize
} }
private fun clientArtemisMessageHandler(artemisMessage: ClientMessage) { private fun clientArtemisMessageHandler(artemisMessage: ClientMessage) {
if (artemisMessage.bodySize > maxMessageSize) { if (artemisMessage.bodySize > amqpConfig.maxMessageSize) {
logWarnWithMDC("Message exceeds maxMessageSize network parameter, maxMessageSize: [$maxMessageSize], message size: [${artemisMessage.bodySize}], " + logWarnWithMDC("Message exceeds maxMessageSize network parameter, maxMessageSize: [${amqpConfig.maxMessageSize}], message size: [${artemisMessage.bodySize}], " +
"dropping message, uuid: ${artemisMessage.getObjectProperty("_AMQ_DUPL_ID")}") "dropping message, uuid: ${artemisMessage.getObjectProperty("_AMQ_DUPL_ID")}")
// Ack the message to prevent same message being sent to us again. // Ack the message to prevent same message being sent to us again.
artemisMessage.acknowledge() artemisMessage.acknowledge()
@ -198,7 +206,7 @@ class AMQPBridgeManager(config: NodeSSLConfiguration, private val maxMessageSize
if (bridgeExists(getBridgeName(queueName, target))) { if (bridgeExists(getBridgeName(queueName, target))) {
return return
} }
val newBridge = AMQPBridge(queueName, target, legalNames, keyStore, keyStorePrivateKeyPassword, trustStore, crlCheckSoftFail, sharedEventLoopGroup!!, artemis!!, maxMessageSize) val newBridge = AMQPBridge(queueName, target, legalNames, amqpConfig, sharedEventLoopGroup!!, artemis!!)
lock.withLock { lock.withLock {
bridgeNameToBridgeMap[newBridge.bridgeName] = newBridge bridgeNameToBridgeMap[newBridge.bridgeName] = newBridge
} }

View File

@ -47,11 +47,15 @@ internal class ConnectionStateMachine(private val serverMode: Boolean,
} }
private fun withMDC(block: () -> Unit) { private fun withMDC(block: () -> Unit) {
MDC.put("serverMode", serverMode.toString()) val oldMDC = MDC.getCopyOfContextMap()
MDC.put("localLegalName", localLegalName) try {
MDC.put("remoteLegalName", remoteLegalName) MDC.put("serverMode", serverMode.toString())
block() MDC.put("localLegalName", localLegalName)
MDC.clear() MDC.put("remoteLegalName", remoteLegalName)
block()
} finally {
MDC.setContextMap(oldMDC)
}
} }
private fun logDebugWithMDC(msg: () -> String) { private fun logDebugWithMDC(msg: () -> String) {

View File

@ -41,11 +41,15 @@ internal class EventProcessor(channel: Channel,
} }
private fun withMDC(block: () -> Unit) { private fun withMDC(block: () -> Unit) {
MDC.put("serverMode", serverMode.toString()) val oldMDC = MDC.getCopyOfContextMap()
MDC.put("localLegalName", localLegalName) try {
MDC.put("remoteLegalName", remoteLegalName) MDC.put("serverMode", serverMode.toString())
block() MDC.put("localLegalName", localLegalName)
MDC.clear() MDC.put("remoteLegalName", remoteLegalName)
block()
} finally {
MDC.setContextMap(oldMDC)
}
} }
private fun logDebugWithMDC(msg: () -> String) { private fun logDebugWithMDC(msg: () -> String) {

View File

@ -23,6 +23,7 @@ import org.slf4j.MDC
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.nio.channels.ClosedChannelException import java.nio.channels.ClosedChannelException
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import javax.net.ssl.SSLException
/** /**
* An instance of AMQPChannelHandler sits inside the netty pipeline and controls the socket level lifecycle. * An instance of AMQPChannelHandler sits inside the netty pipeline and controls the socket level lifecycle.
@ -48,13 +49,17 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
private var badCert: Boolean = false private var badCert: Boolean = false
private fun withMDC(block: () -> Unit) { private fun withMDC(block: () -> Unit) {
MDC.put("serverMode", serverMode.toString()) val oldMDC = MDC.getCopyOfContextMap()
MDC.put("remoteAddress", remoteAddress.toString()) try {
MDC.put("localCert", localCert?.subjectDN?.toString()) MDC.put("serverMode", serverMode.toString())
MDC.put("remoteCert", remoteCert?.subjectDN?.toString()) MDC.put("remoteAddress", remoteAddress.toString())
MDC.put("allowedRemoteLegalNames", allowedRemoteLegalNames?.joinToString(separator = ";") { it.toString() }) MDC.put("localCert", localCert?.subjectDN?.toString())
block() MDC.put("remoteCert", remoteCert?.subjectDN?.toString())
MDC.clear() MDC.put("allowedRemoteLegalNames", allowedRemoteLegalNames?.joinToString(separator = ";") { it.toString() })
block()
} finally {
MDC.setContextMap(oldMDC)
}
} }
private fun logDebugWithMDC(msg: () -> String) { private fun logDebugWithMDC(msg: () -> String) {
@ -129,9 +134,12 @@ internal class AMQPChannelHandler(private val serverMode: Boolean,
createAMQPEngine(ctx) createAMQPEngine(ctx)
onOpen(Pair(ctx.channel() as SocketChannel, ConnectionChange(remoteAddress, remoteCert, true, false))) onOpen(Pair(ctx.channel() as SocketChannel, ConnectionChange(remoteAddress, remoteCert, true, false)))
} else { } else {
val cause = evt.cause()
// This happens when the peer node is closed during SSL establishment. // This happens when the peer node is closed during SSL establishment.
if (evt.cause() is ClosedChannelException) { if (cause is ClosedChannelException) {
logWarnWithMDC("SSL Handshake closed early.") logWarnWithMDC("SSL Handshake closed early.")
} else if (cause is SSLException && cause.message == "handshake timed out") { // Sadly the exception thrown by Netty wrapper requires that we check the message.
logWarnWithMDC("SSL Handshake timed out")
} else { } else {
badCert = true badCert = true
} }

View File

@ -19,7 +19,6 @@ import net.corda.nodeapi.internal.requireMessageSize
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.lang.Long.min import java.lang.Long.min
import java.security.KeyStore
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import javax.net.ssl.KeyManagerFactory import javax.net.ssl.KeyManagerFactory
@ -35,15 +34,8 @@ import kotlin.concurrent.withLock
*/ */
class AMQPClient(val targets: List<NetworkHostAndPort>, class AMQPClient(val targets: List<NetworkHostAndPort>,
val allowedRemoteLegalNames: Set<CordaX500Name>, val allowedRemoteLegalNames: Set<CordaX500Name>,
private val userName: String?, private val configuration: AMQPConfiguration,
private val password: String?, private val sharedThreadPool: EventLoopGroup? = null) : AutoCloseable {
private val keyStore: KeyStore,
private val keyStorePrivateKeyPassword: String,
private val trustStore: KeyStore,
private val crlCheckSoftFail: Boolean,
private val trace: Boolean = false,
private val sharedThreadPool: EventLoopGroup? = null,
private val maxMessageSize: Int) : AutoCloseable {
companion object { companion object {
init { init {
InternalLoggerFactory.setDefaultFactory(Slf4JLoggerFactory.INSTANCE) InternalLoggerFactory.setDefaultFactory(Slf4JLoggerFactory.INSTANCE)
@ -121,10 +113,11 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
private class ClientChannelInitializer(val parent: AMQPClient) : ChannelInitializer<SocketChannel>() { private class ClientChannelInitializer(val parent: AMQPClient) : ChannelInitializer<SocketChannel>() {
private val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) private val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
private val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) private val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
private val conf = parent.configuration
init { init {
keyManagerFactory.init(parent.keyStore, parent.keyStorePrivateKeyPassword.toCharArray()) keyManagerFactory.init(conf.keyStore, conf.keyStorePrivateKeyPassword)
trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(parent.trustStore, parent.crlCheckSoftFail)) trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(conf.trustStore, conf.crlCheckSoftFail))
} }
override fun initChannel(ch: SocketChannel) { override fun initChannel(ch: SocketChannel) {
@ -132,12 +125,12 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
val target = parent.currentTarget val target = parent.currentTarget
val handler = createClientSslHelper(target, keyManagerFactory, trustManagerFactory) val handler = createClientSslHelper(target, keyManagerFactory, trustManagerFactory)
pipeline.addLast("sslHandler", handler) pipeline.addLast("sslHandler", handler)
if (parent.trace) pipeline.addLast("logger", LoggingHandler(LogLevel.INFO)) if (conf.trace) pipeline.addLast("logger", LoggingHandler(LogLevel.INFO))
pipeline.addLast(AMQPChannelHandler(false, pipeline.addLast(AMQPChannelHandler(false,
parent.allowedRemoteLegalNames, parent.allowedRemoteLegalNames,
parent.userName, conf.userName,
parent.password, conf.password,
parent.trace, conf.trace,
{ {
parent.retryInterval = MIN_RETRY_INTERVAL // reset to fast reconnect if we connect properly parent.retryInterval = MIN_RETRY_INTERVAL // reset to fast reconnect if we connect properly
parent._onConnection.onNext(it.second) parent._onConnection.onNext(it.second)
@ -205,7 +198,7 @@ class AMQPClient(val targets: List<NetworkHostAndPort>,
topic: String, topic: String,
destinationLegalName: String, destinationLegalName: String,
properties: Map<String, Any?>): SendableMessage { properties: Map<String, Any?>): SendableMessage {
requireMessageSize(payload.size, maxMessageSize) requireMessageSize(payload.size, configuration.maxMessageSize)
return SendableMessageImpl(payload, topic, destinationLegalName, currentTarget, properties) return SendableMessageImpl(payload, topic, destinationLegalName, currentTarget, properties)
} }

View File

@ -0,0 +1,59 @@
package net.corda.nodeapi.internal.protonwrapper.netty
import net.corda.nodeapi.internal.ArtemisMessagingComponent
import java.security.KeyStore
interface AMQPConfiguration {
/**
* SASL User name presented during protocol handshake. No SASL login if NULL.
* For legacy interoperability with Artemis authorisation we typically require this to be "PEER_USER"
*/
@JvmDefault
val userName: String?
get() = ArtemisMessagingComponent.PEER_USER
/**
* SASL plain text password presented during protocol handshake. No SASL login if NULL.
* For legacy interoperability with Artemis authorisation we typically require this to be "PEER_USER"
*/
@JvmDefault
val password: String?
get() = ArtemisMessagingComponent.PEER_USER
/**
* The keystore used for TLS connections
*/
val keyStore: KeyStore
/**
* Password used to unlock TLS private keys in the KeyStore.
*/
val keyStorePrivateKeyPassword: CharArray
/**
* The trust root KeyStore to validate the peer certificates against
*/
val trustStore: KeyStore
/**
* Setting crlCheckSoftFail to true allows certificate paths where some leaf certificates do not contain cRLDistributionPoints
* and also allows validation to continue if the CRL distribution server is not contactable.
*/
@JvmDefault
val crlCheckSoftFail: Boolean
get() = true
/**
* Enables full debug tracing of all netty and AMQP level packets. This logs aat very high volume and is only for developers.
*/
@JvmDefault
val trace: Boolean
get() = false
/**
* The maximum allowed size for packets, which will be dropped ahead of send. In future may also be enforced on receive,
* but currently that is deferred to Artemis and the bridge code.
*/
val maxMessageSize: Int
}

View File

@ -23,7 +23,6 @@ import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.net.BindException import java.net.BindException
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.security.KeyStore
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import javax.net.ssl.KeyManagerFactory import javax.net.ssl.KeyManagerFactory
@ -36,14 +35,7 @@ import kotlin.concurrent.withLock
*/ */
class AMQPServer(val hostName: String, class AMQPServer(val hostName: String,
val port: Int, val port: Int,
private val userName: String?, private val configuration: AMQPConfiguration) : AutoCloseable {
private val password: String?,
private val keyStore: KeyStore,
private val keyStorePrivateKeyPassword: CharArray,
private val trustStore: KeyStore,
private val crlCheckSoftFail: Boolean,
private val trace: Boolean = false,
private val maxMessageSize: Int) : AutoCloseable {
companion object { companion object {
init { init {
@ -62,36 +54,26 @@ class AMQPServer(val hostName: String,
private var serverChannel: Channel? = null private var serverChannel: Channel? = null
private val clientChannels = ConcurrentHashMap<InetSocketAddress, SocketChannel>() private val clientChannels = ConcurrentHashMap<InetSocketAddress, SocketChannel>()
constructor(hostName: String,
port: Int,
userName: String?,
password: String?,
keyStore: KeyStore,
keyStorePrivateKeyPassword: String,
trustStore: KeyStore,
crlCheckSoftFail: Boolean,
trace: Boolean = false,
maxMessageSize: Int) : this(hostName, port, userName, password, keyStore, keyStorePrivateKeyPassword.toCharArray(), trustStore, crlCheckSoftFail, trace, maxMessageSize)
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())
private val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) private val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
private val conf = parent.configuration
init { init {
keyManagerFactory.init(parent.keyStore, parent.keyStorePrivateKeyPassword) keyManagerFactory.init(conf.keyStore, conf.keyStorePrivateKeyPassword)
trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(parent.trustStore, parent.crlCheckSoftFail)) trustManagerFactory.init(initialiseTrustStoreAndEnableCrlChecking(conf.trustStore, conf.crlCheckSoftFail))
} }
override fun initChannel(ch: SocketChannel) { override fun initChannel(ch: SocketChannel) {
val pipeline = ch.pipeline() val pipeline = ch.pipeline()
val handler = createServerSslHelper(keyManagerFactory, trustManagerFactory) val handler = createServerSslHelper(keyManagerFactory, trustManagerFactory)
pipeline.addLast("sslHandler", handler) pipeline.addLast("sslHandler", handler)
if (parent.trace) pipeline.addLast("logger", LoggingHandler(LogLevel.INFO)) if (conf.trace) pipeline.addLast("logger", LoggingHandler(LogLevel.INFO))
pipeline.addLast(AMQPChannelHandler(true, pipeline.addLast(AMQPChannelHandler(true,
null, null,
parent.userName, conf.userName,
parent.password, conf.password,
parent.trace, conf.trace,
{ {
parent.clientChannels[it.first.remoteAddress()] = it.first parent.clientChannels[it.first.remoteAddress()] = it.first
parent._onConnection.onNext(it.second) parent._onConnection.onNext(it.second)
@ -159,7 +141,7 @@ class AMQPServer(val hostName: String,
destinationLegalName: String, destinationLegalName: String,
destinationLink: NetworkHostAndPort, destinationLink: NetworkHostAndPort,
properties: Map<String, Any?>): SendableMessage { properties: Map<String, Any?>): SendableMessage {
requireMessageSize(payload.size, maxMessageSize) requireMessageSize(payload.size, configuration.maxMessageSize)
val dest = InetSocketAddress(destinationLink.host, destinationLink.port) val dest = InetSocketAddress(destinationLink.host, destinationLink.port)
require(dest in clientChannels.keys) { require(dest in clientChannels.keys) {
"Destination not available" "Destination not available"

View File

@ -6,15 +6,14 @@ import net.corda.core.crypto.toStringShort
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.services.config.CertChainPolicyConfig
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.configureWithDevSSLCertificate import net.corda.node.services.config.configureWithDevSSLCertificate
import net.corda.node.services.messaging.ArtemisMessagingServer import net.corda.node.services.messaging.ArtemisMessagingServer
import net.corda.nodeapi.internal.ArtemisMessagingClient import net.corda.nodeapi.internal.ArtemisMessagingClient
import net.corda.nodeapi.internal.ArtemisMessagingComponent
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2PMessagingHeaders import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2PMessagingHeaders
import net.corda.nodeapi.internal.bridging.AMQPBridgeManager import net.corda.nodeapi.internal.bridging.AMQPBridgeManager
import net.corda.nodeapi.internal.bridging.BridgeManager import net.corda.nodeapi.internal.bridging.BridgeManager
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
@ -25,6 +24,7 @@ import org.junit.Assert.assertArrayEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.security.KeyStore
import java.util.* import java.util.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -201,16 +201,16 @@ class AMQPBridgeTest {
} }
serverConfig.configureWithDevSSLCertificate() serverConfig.configureWithDevSSLCertificate()
val amqpConfig = object : AMQPConfiguration {
override val keyStore: KeyStore = serverConfig.loadSslKeyStore().internal
override val keyStorePrivateKeyPassword: CharArray = serverConfig.keyStorePassword.toCharArray()
override val trustStore: KeyStore = serverConfig.loadTrustStore().internal
override val trace: Boolean = true
override val maxMessageSize: Int = maxMessageSize
}
return AMQPServer("0.0.0.0", return AMQPServer("0.0.0.0",
amqpPort, amqpPort,
ArtemisMessagingComponent.PEER_USER, amqpConfig
ArtemisMessagingComponent.PEER_USER,
serverConfig.loadSslKeyStore().internal,
serverConfig.keyStorePassword,
serverConfig.loadTrustStore().internal,
crlCheckSoftFail = true,
trace = true,
maxMessageSize = maxMessageSize
) )
} }
} }

View File

@ -13,11 +13,11 @@ import net.corda.core.utilities.seconds
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.configureWithDevSSLCertificate import net.corda.node.services.config.configureWithDevSSLCertificate
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2P_PREFIX 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.config.SSLConfiguration
import net.corda.nodeapi.internal.crypto.* import net.corda.nodeapi.internal.crypto.*
import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.internal.DEV_INTERMEDIATE_CA import net.corda.testing.internal.DEV_INTERMEDIATE_CA
@ -46,6 +46,7 @@ import java.io.Closeable
import java.math.BigInteger import java.math.BigInteger
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.security.KeyPair import java.security.KeyPair
import java.security.KeyStore
import java.security.PrivateKey import java.security.PrivateKey
import java.security.Security import java.security.Security
import java.security.cert.X509CRL import java.security.cert.X509CRL
@ -244,7 +245,7 @@ class CertificateRevocationListNodeTests {
@Test @Test
fun `AMPQ Client to Server connection succeeds when CRL cannot be obtained and soft fail is enabled`() { fun `AMPQ Client to Server connection succeeds when CRL cannot be obtained and soft fail is enabled`() {
val crlCheckSoftFail = true val crlCheckSoftFail = true
val (amqpServer, serverCert) = createServer( val (amqpServer, _) = createServer(
serverPort, serverPort,
crlCheckSoftFail = crlCheckSoftFail, crlCheckSoftFail = crlCheckSoftFail,
nodeCrlDistPoint = "http://${server.hostAndPort}/crl/invalid.crl") nodeCrlDistPoint = "http://${server.hostAndPort}/crl/invalid.crl")
@ -335,16 +336,18 @@ class CertificateRevocationListNodeTests {
val nodeCert = clientConfig.recreateNodeCaAndTlsCertificates(nodeCrlDistPoint, tlsCrlDistPoint) val nodeCert = clientConfig.recreateNodeCaAndTlsCertificates(nodeCrlDistPoint, tlsCrlDistPoint)
val clientTruststore = clientConfig.loadTrustStore().internal val clientTruststore = clientConfig.loadTrustStore().internal
val clientKeystore = clientConfig.loadSslKeyStore().internal val clientKeystore = clientConfig.loadSslKeyStore().internal
val amqpConfig = object : AMQPConfiguration {
override val keyStore: KeyStore = clientKeystore
override val keyStorePrivateKeyPassword: CharArray = clientConfig.keyStorePassword.toCharArray()
override val trustStore: KeyStore = clientTruststore
override val crlCheckSoftFail: Boolean = crlCheckSoftFail
override val maxMessageSize: Int = maxMessageSize
}
return Pair(AMQPClient( return Pair(AMQPClient(
listOf(NetworkHostAndPort("localhost", targetPort)), listOf(NetworkHostAndPort("localhost", targetPort)),
setOf(ALICE_NAME, CHARLIE_NAME), setOf(ALICE_NAME, CHARLIE_NAME),
PEER_USER, amqpConfig), nodeCert)
PEER_USER,
clientKeystore,
clientConfig.keyStorePassword,
clientTruststore,
crlCheckSoftFail,
maxMessageSize = maxMessageSize), nodeCert)
} }
private fun createServer(port: Int, name: CordaX500Name = ALICE_NAME, private fun createServer(port: Int, name: CordaX500Name = ALICE_NAME,
@ -363,16 +366,17 @@ class CertificateRevocationListNodeTests {
val nodeCert = serverConfig.recreateNodeCaAndTlsCertificates(nodeCrlDistPoint, tlsCrlDistPoint) val nodeCert = serverConfig.recreateNodeCaAndTlsCertificates(nodeCrlDistPoint, tlsCrlDistPoint)
val serverTruststore = serverConfig.loadTrustStore().internal val serverTruststore = serverConfig.loadTrustStore().internal
val serverKeystore = serverConfig.loadSslKeyStore().internal val serverKeystore = serverConfig.loadSslKeyStore().internal
val amqpConfig = object : AMQPConfiguration {
override val keyStore: KeyStore = serverKeystore
override val keyStorePrivateKeyPassword: CharArray = serverConfig.keyStorePassword.toCharArray()
override val trustStore: KeyStore = serverTruststore
override val crlCheckSoftFail: Boolean = crlCheckSoftFail
override val maxMessageSize: Int = maxMessageSize
}
return Pair(AMQPServer( return Pair(AMQPServer(
"0.0.0.0", "0.0.0.0",
port, port,
PEER_USER, amqpConfig), nodeCert)
PEER_USER,
serverKeystore,
serverConfig.keyStorePassword,
serverTruststore,
crlCheckSoftFail,
maxMessageSize = maxMessageSize), nodeCert)
} }
private fun SSLConfiguration.recreateNodeCaAndTlsCertificates(nodeCaCrlDistPoint: String, tlsCrlDistPoint: String?): X509Certificate { private fun SSLConfiguration.recreateNodeCaAndTlsCertificates(nodeCaCrlDistPoint: String, tlsCrlDistPoint: String?): X509Certificate {

View File

@ -8,19 +8,18 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.toFuture import net.corda.core.toFuture
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.services.config.CertChainPolicyConfig
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.configureWithDevSSLCertificate import net.corda.node.services.config.configureWithDevSSLCertificate
import net.corda.node.services.messaging.ArtemisMessagingServer import net.corda.node.services.messaging.ArtemisMessagingServer
import net.corda.nodeapi.ArtemisTcpTransport.Companion.CIPHER_SUITES import net.corda.nodeapi.ArtemisTcpTransport.Companion.CIPHER_SUITES
import net.corda.nodeapi.internal.ArtemisMessagingClient import net.corda.nodeapi.internal.ArtemisMessagingClient
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.P2P_PREFIX 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.config.SSLConfiguration
import net.corda.nodeapi.internal.createDevKeyStores import net.corda.nodeapi.internal.createDevKeyStores
import net.corda.nodeapi.internal.crypto.* import net.corda.nodeapi.internal.crypto.*
import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus import net.corda.nodeapi.internal.protonwrapper.messages.MessageStatus
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient import net.corda.nodeapi.internal.protonwrapper.netty.AMQPClient
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPConfiguration
import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer import net.corda.nodeapi.internal.protonwrapper.netty.AMQPServer
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.internal.createDevIntermediateCaCertPath import net.corda.testing.internal.createDevIntermediateCaCertPath
@ -31,6 +30,7 @@ import org.junit.Assert.assertArrayEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.security.KeyStore
import java.security.SecureRandom import java.security.SecureRandom
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import javax.net.ssl.* import javax.net.ssl.*
@ -388,18 +388,19 @@ class ProtonWrapperTests {
val clientTruststore = clientConfig.loadTrustStore().internal val clientTruststore = clientConfig.loadTrustStore().internal
val clientKeystore = clientConfig.loadSslKeyStore().internal val clientKeystore = clientConfig.loadSslKeyStore().internal
val amqpConfig = object : AMQPConfiguration {
override val keyStore: KeyStore = clientKeystore
override val keyStorePrivateKeyPassword: CharArray = clientConfig.keyStorePassword.toCharArray()
override val trustStore: KeyStore = clientTruststore
override val trace: Boolean = true
override val maxMessageSize: Int = maxMessageSize
}
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, amqpConfig)
PEER_USER,
clientKeystore,
clientConfig.keyStorePassword,
clientTruststore,
true,
maxMessageSize = maxMessageSize)
} }
private fun createSharedThreadsClient(sharedEventGroup: EventLoopGroup, id: Int, maxMessageSize: Int = MAX_MESSAGE_SIZE): AMQPClient { private fun createSharedThreadsClient(sharedEventGroup: EventLoopGroup, id: Int, maxMessageSize: Int = MAX_MESSAGE_SIZE): AMQPClient {
@ -414,17 +415,18 @@ class ProtonWrapperTests {
val clientTruststore = clientConfig.loadTrustStore().internal val clientTruststore = clientConfig.loadTrustStore().internal
val clientKeystore = clientConfig.loadSslKeyStore().internal val clientKeystore = clientConfig.loadSslKeyStore().internal
val amqpConfig = object : AMQPConfiguration {
override val keyStore: KeyStore = clientKeystore
override val keyStorePrivateKeyPassword: CharArray = clientConfig.keyStorePassword.toCharArray()
override val trustStore: KeyStore = clientTruststore
override val trace: Boolean = true
override val maxMessageSize: Int = maxMessageSize
}
return AMQPClient( return AMQPClient(
listOf(NetworkHostAndPort("localhost", serverPort)), listOf(NetworkHostAndPort("localhost", serverPort)),
setOf(ALICE_NAME), setOf(ALICE_NAME),
PEER_USER, amqpConfig,
PEER_USER, sharedThreadPool = sharedEventGroup)
clientKeystore,
clientConfig.keyStorePassword,
clientTruststore,
true,
sharedThreadPool = sharedEventGroup,
maxMessageSize = maxMessageSize)
} }
private fun createServer(port: Int, name: CordaX500Name = ALICE_NAME, maxMessageSize: Int = MAX_MESSAGE_SIZE): AMQPServer { private fun createServer(port: Int, name: CordaX500Name = ALICE_NAME, maxMessageSize: Int = MAX_MESSAGE_SIZE): AMQPServer {
@ -439,15 +441,16 @@ class ProtonWrapperTests {
val serverTruststore = serverConfig.loadTrustStore().internal val serverTruststore = serverConfig.loadTrustStore().internal
val serverKeystore = serverConfig.loadSslKeyStore().internal val serverKeystore = serverConfig.loadSslKeyStore().internal
val amqpConfig = object : AMQPConfiguration {
override val keyStore: KeyStore = serverKeystore
override val keyStorePrivateKeyPassword: CharArray = serverConfig.keyStorePassword.toCharArray()
override val trustStore: KeyStore = serverTruststore
override val trace: Boolean = true
override val maxMessageSize: Int = maxMessageSize
}
return AMQPServer( return AMQPServer(
"0.0.0.0", "0.0.0.0",
port, port,
PEER_USER, amqpConfig)
PEER_USER,
serverKeystore,
serverConfig.keyStorePassword,
serverTruststore,
crlCheckSoftFail = true,
maxMessageSize = maxMessageSize)
} }
} }