Make SSL optional in the RPC client

This commit is contained in:
Mike Hearn
2017-01-06 11:41:40 +01:00
parent 15363e686a
commit 20dbdf9d1b
2 changed files with 44 additions and 35 deletions

View File

@ -19,10 +19,9 @@ import java.nio.file.Path
import java.security.KeyStore import java.security.KeyStore
/** /**
* The base class for Artemis services that defines shared data structures and transport configuration * The base class for Artemis services that defines shared data structures and SSL transport configuration.
*/ */
abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() { abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
companion object { companion object {
init { init {
System.setProperty("org.jboss.logging.provider", "slf4j") System.setProperty("org.jboss.logging.provider", "slf4j")
@ -106,7 +105,7 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
} }
/** The config object is used to pass in the passwords for the certificate KeyStore and TrustStore */ /** The config object is used to pass in the passwords for the certificate KeyStore and TrustStore */
abstract val config: NodeSSLConfiguration abstract val config: NodeSSLConfiguration?
// Restrict enabled Cipher Suites to AES and GCM as minimum for the bulk cipher. // Restrict enabled Cipher Suites to AES and GCM as minimum for the bulk cipher.
// Our self-generated certificates all use ECDSA for handshakes, but we allow classical RSA certificates to work // Our self-generated certificates all use ECDSA for handshakes, but we allow classical RSA certificates to work
@ -126,6 +125,7 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
* unfortunately Artemis tends to bury the exception when the password is wrong. * unfortunately Artemis tends to bury the exception when the password is wrong.
*/ */
fun checkStorePasswords() { fun checkStorePasswords() {
val config = config ?: return
config.keyStorePath.read { config.keyStorePath.read {
KeyStore.getInstance("JKS").load(it, config.keyStorePassword.toCharArray()) KeyStore.getInstance("JKS").load(it, config.keyStorePassword.toCharArray())
} }
@ -135,14 +135,8 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
} }
protected fun tcpTransport(direction: ConnectionDirection, host: String, port: Int): TransportConfiguration { protected fun tcpTransport(direction: ConnectionDirection, host: String, port: Int): TransportConfiguration {
config.keyStorePath.expectedOnDefaultFileSystem() val config = config
config.trustStorePath.expectedOnDefaultFileSystem() val options = mutableMapOf<String, Any?>(
return TransportConfiguration(
when (direction) {
is Inbound -> NettyAcceptorFactory::class.java.name
is Outbound -> VerifyingNettyConnectorFactory::class.java.name
},
mapOf(
// Basic TCP target details // Basic TCP target details
TransportConstants.HOST_PROP_NAME to host, TransportConstants.HOST_PROP_NAME to host,
TransportConstants.PORT_PROP_NAME to port, TransportConstants.PORT_PROP_NAME to port,
@ -151,8 +145,13 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
// Unfortunately we cannot disable core protocol as artemis only uses AMQP for interop // Unfortunately we cannot disable core protocol as artemis only uses AMQP for interop
// It does not use AMQP messages for its own messages e.g. topology and heartbeats // It does not use AMQP messages for its own messages e.g. topology and heartbeats
// TODO further investigate how to ensure we use a well defined wire level protocol for Node to Node communications // TODO further investigate how to ensure we use a well defined wire level protocol for Node to Node communications
TransportConstants.PROTOCOLS_PROP_NAME to "CORE,AMQP", TransportConstants.PROTOCOLS_PROP_NAME to "CORE,AMQP"
)
if (config != null) {
config.keyStorePath.expectedOnDefaultFileSystem()
config.trustStorePath.expectedOnDefaultFileSystem()
val tlsOptions = mapOf<String, Any?>(
// Enable TLS transport layer with client certs and restrict to at least SHA256 in handshake // Enable TLS transport layer with client certs and restrict to at least SHA256 in handshake
// and AES encryption // and AES encryption
TransportConstants.SSL_ENABLED_PROP_NAME to true, TransportConstants.SSL_ENABLED_PROP_NAME to true,
@ -167,7 +166,13 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
TransportConstants.NEED_CLIENT_AUTH_PROP_NAME to true, TransportConstants.NEED_CLIENT_AUTH_PROP_NAME to true,
VERIFY_PEER_COMMON_NAME to (direction as? Outbound)?.expectedCommonName VERIFY_PEER_COMMON_NAME to (direction as? Outbound)?.expectedCommonName
) )
) options.putAll(tlsOptions)
}
val factoryName = when (direction) {
is Inbound -> NettyAcceptorFactory::class.java.name
is Outbound -> VerifyingNettyConnectorFactory::class.java.name
}
return TransportConfiguration(factoryName, options)
} }
protected fun Path.expectedOnDefaultFileSystem() { protected fun Path.expectedOnDefaultFileSystem() {

View File

@ -17,9 +17,12 @@ import javax.annotation.concurrent.ThreadSafe
/** /**
* An RPC client connects to the specified server and allows you to make calls to the server that perform various * An RPC client connects to the specified server and allows you to make calls to the server that perform various
* useful tasks. See the documentation for [proxy] or review the docsite to learn more about how this API works. * useful tasks. See the documentation for [proxy] or review the docsite to learn more about how this API works.
*
* @param host The hostname and messaging port of the node.
* @param config If specified, the SSL configuration to use. If not specified, SSL will be disabled and the node will not be authenticated, nor will RPC traffic be encrypted.
*/ */
@ThreadSafe @ThreadSafe
class CordaRPCClient(val host: HostAndPort, override val config: NodeSSLConfiguration) : Closeable, ArtemisMessagingComponent() { class CordaRPCClient(val host: HostAndPort, override val config: NodeSSLConfiguration?) : Closeable, ArtemisMessagingComponent() {
// TODO: Certificate handling for clients needs more work. // TODO: Certificate handling for clients needs more work.
private inner class State { private inner class State {
var running = false var running = false
@ -106,6 +109,7 @@ class CordaRPCClient(val host: HostAndPort, override val config: NodeSSLConfigur
} }
} }
@Suppress("UNUSED")
private fun finalize() { private fun finalize() {
state.locked { state.locked {
if (running) { if (running) {