mirror of
https://github.com/corda/corda.git
synced 2025-01-05 12:44:21 +00:00
Add :node-api, factor out some artemis code
This commit is contained in:
parent
486368d926
commit
c3c1f3d801
@ -2,6 +2,7 @@ package net.corda.client.model
|
|||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.flows.StateMachineRunId
|
import net.corda.core.flows.StateMachineRunId
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.StateMachineInfo
|
import net.corda.core.messaging.StateMachineInfo
|
||||||
@ -11,7 +12,6 @@ import net.corda.core.node.services.StateMachineTransactionMapping
|
|||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.seconds
|
import net.corda.core.seconds
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.messaging.CordaRPCClient
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
|
52
node-api/build.gradle
Normal file
52
node-api/build.gradle
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
apply plugin: 'kotlin'
|
||||||
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
|
apply plugin: 'net.corda.plugins.publish-utils'
|
||||||
|
|
||||||
|
description 'Corda node Artemis API'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
|
maven {
|
||||||
|
url 'http://oss.sonatype.org/content/repositories/snapshots'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url 'https://dl.bintray.com/kotlin/exposed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
test {
|
||||||
|
resources {
|
||||||
|
srcDir "../config/test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
resources {
|
||||||
|
srcDir "../config/dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(":core")
|
||||||
|
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
|
compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.3"
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
compile "org.apache.activemq:artemis-server:${artemis_version}"
|
||||||
|
compile "org.apache.activemq:artemis-core-client:${artemis_version}"
|
||||||
|
compile "org.apache.activemq:artemis-commons:${artemis_version}"
|
||||||
|
runtime "org.apache.activemq:artemis-amqp-protocol:${artemis_version}"
|
||||||
|
|
||||||
|
// TypeSafe Config: for simple and human friendly config files.
|
||||||
|
compile "com.typesafe:config:$typesafe_config_version"
|
||||||
|
}
|
75
node-api/src/main/kotlin/net/corda/config/ConfigUtilities.kt
Normal file
75
node-api/src/main/kotlin/net/corda/config/ConfigUtilities.kt
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package net.corda.config
|
||||||
|
|
||||||
|
import com.google.common.net.HostAndPort
|
||||||
|
import com.typesafe.config.Config
|
||||||
|
import java.net.URL
|
||||||
|
import java.nio.file.FileSystems
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.jvm.javaType
|
||||||
|
|
||||||
|
private fun <T : Enum<T>> enumBridge(clazz: Class<T>, enumValueString: String): T {
|
||||||
|
return java.lang.Enum.valueOf(clazz, enumValueString)
|
||||||
|
}
|
||||||
|
private class DummyEnum : Enum<DummyEnum>("", 0)
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST", "PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||||
|
operator fun <T> Config.getValue(receiver: Any, metadata: KProperty<*>): T {
|
||||||
|
if (metadata.returnType.isMarkedNullable && !hasPath(metadata.name)) {
|
||||||
|
return null as T
|
||||||
|
}
|
||||||
|
val returnType = metadata.returnType.javaType
|
||||||
|
return when (metadata.returnType.javaType) {
|
||||||
|
String::class.java -> getString(metadata.name) as T
|
||||||
|
Int::class.java -> getInt(metadata.name) as T
|
||||||
|
Integer::class.java -> getInt(metadata.name) as T
|
||||||
|
Long::class.java -> getLong(metadata.name) as T
|
||||||
|
Double::class.java -> getDouble(metadata.name) as T
|
||||||
|
Boolean::class.java -> getBoolean(metadata.name) as T
|
||||||
|
LocalDate::class.java -> LocalDate.parse(getString(metadata.name)) as T
|
||||||
|
Instant::class.java -> Instant.parse(getString(metadata.name)) as T
|
||||||
|
HostAndPort::class.java -> HostAndPort.fromString(getString(metadata.name)) as T
|
||||||
|
Path::class.java -> Paths.get(getString(metadata.name)) as T
|
||||||
|
URL::class.java -> URL(getString(metadata.name)) as T
|
||||||
|
Properties::class.java -> getProperties(metadata.name) as T
|
||||||
|
else -> {
|
||||||
|
if (returnType is Class<*> && Enum::class.java.isAssignableFrom(returnType)) {
|
||||||
|
return enumBridge(returnType as Class<DummyEnum>, getString(metadata.name)) as T
|
||||||
|
}
|
||||||
|
throw IllegalArgumentException("Unsupported type ${metadata.returnType}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for optional configurations
|
||||||
|
*/
|
||||||
|
class OptionalConfig<out T>(val conf: Config, val lambda: () -> T) {
|
||||||
|
operator fun getValue(receiver: Any, metadata: KProperty<*>): T {
|
||||||
|
return if (conf.hasPath(metadata.name)) conf.getValue(receiver, metadata) else lambda()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Config.getOrElse(lambda: () -> T): OptionalConfig<T> = OptionalConfig(this, lambda)
|
||||||
|
|
||||||
|
fun Config.getProperties(path: String): Properties {
|
||||||
|
val obj = this.getObject(path)
|
||||||
|
val props = Properties()
|
||||||
|
for ((property, objectValue) in obj.entries) {
|
||||||
|
props.setProperty(property, objectValue.unwrapped().toString())
|
||||||
|
}
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
inline fun <reified T : Any> Config.getListOrElse(path: String, default: Config.() -> List<T>): List<T> {
|
||||||
|
return if (hasPath(path)) {
|
||||||
|
(if (T::class == String::class) getStringList(path) else getConfigList(path)) as List<T>
|
||||||
|
} else {
|
||||||
|
this.default()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package net.corda.config
|
||||||
|
|
||||||
|
import net.corda.core.div
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
interface SSLConfiguration {
|
||||||
|
val keyStorePassword: String
|
||||||
|
val trustStorePassword: String
|
||||||
|
val certificatesDirectory: Path
|
||||||
|
val keyStoreFile: Path get() = certificatesDirectory / "sslkeystore.jks"
|
||||||
|
val trustStoreFile: Path get() = certificatesDirectory / "truststore.jks"
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package net.corda.node
|
||||||
|
|
||||||
|
import com.google.common.net.HostAndPort
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
|
import org.apache.activemq.artemis.api.core.TransportConfiguration
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory
|
||||||
|
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants
|
||||||
|
import java.nio.file.FileSystems
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
sealed class ConnectionDirection {
|
||||||
|
object Inbound : ConnectionDirection()
|
||||||
|
class Outbound(val expectedCommonName: String? = null) : ConnectionDirection()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArtemisTcpTransport {
|
||||||
|
companion object {
|
||||||
|
const val VERIFY_PEER_COMMON_NAME = "corda.verifyPeerCommonName"
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// in case we need to use keytool certificates in some demos
|
||||||
|
private val CIPHER_SUITES = listOf(
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun tcpTransport(
|
||||||
|
direction: ConnectionDirection,
|
||||||
|
hostAndPort: HostAndPort,
|
||||||
|
config: SSLConfiguration?,
|
||||||
|
acceptorFactoryClassName: String = NettyAcceptorFactory::class.java.name,
|
||||||
|
connectorFactoryClassName: String = NettyConnectorFactory::class.java.name,
|
||||||
|
enableSSL: Boolean = true
|
||||||
|
): TransportConfiguration {
|
||||||
|
val options = mutableMapOf<String, Any?>(
|
||||||
|
// Basic TCP target details
|
||||||
|
TransportConstants.HOST_PROP_NAME to hostAndPort.hostText,
|
||||||
|
TransportConstants.PORT_PROP_NAME to hostAndPort.port,
|
||||||
|
|
||||||
|
// Turn on AMQP support, which needs the protocol jar on the classpath.
|
||||||
|
// 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
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (config != null && enableSSL) {
|
||||||
|
config.keyStoreFile.expectedOnDefaultFileSystem()
|
||||||
|
config.trustStoreFile.expectedOnDefaultFileSystem()
|
||||||
|
val tlsOptions = mapOf<String, Any?>(
|
||||||
|
// Enable TLS transport layer with client certs and restrict to at least SHA256 in handshake
|
||||||
|
// and AES encryption
|
||||||
|
TransportConstants.SSL_ENABLED_PROP_NAME to true,
|
||||||
|
TransportConstants.KEYSTORE_PROVIDER_PROP_NAME to "JKS",
|
||||||
|
TransportConstants.KEYSTORE_PATH_PROP_NAME to config.keyStoreFile,
|
||||||
|
TransportConstants.KEYSTORE_PASSWORD_PROP_NAME to config.keyStorePassword, // TODO proper management of keystores and password
|
||||||
|
TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME to "JKS",
|
||||||
|
TransportConstants.TRUSTSTORE_PATH_PROP_NAME to config.trustStoreFile,
|
||||||
|
TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME to config.trustStorePassword,
|
||||||
|
TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME to CIPHER_SUITES.joinToString(","),
|
||||||
|
TransportConstants.ENABLED_PROTOCOLS_PROP_NAME to "TLSv1.2",
|
||||||
|
TransportConstants.NEED_CLIENT_AUTH_PROP_NAME to true,
|
||||||
|
VERIFY_PEER_COMMON_NAME to (direction as? ConnectionDirection.Outbound)?.expectedCommonName
|
||||||
|
)
|
||||||
|
options.putAll(tlsOptions)
|
||||||
|
}
|
||||||
|
val factoryName = when (direction) {
|
||||||
|
is ConnectionDirection.Inbound -> acceptorFactoryClassName
|
||||||
|
is ConnectionDirection.Outbound -> connectorFactoryClassName
|
||||||
|
}
|
||||||
|
return TransportConfiguration(factoryName, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Path.expectedOnDefaultFileSystem() {
|
||||||
|
require(fileSystem == FileSystems.getDefault()) { "Artemis only uses the default file system" }
|
||||||
|
}
|
@ -68,6 +68,7 @@ dependencies {
|
|||||||
compile (project(':node-schemas')) {
|
compile (project(':node-schemas')) {
|
||||||
exclude group: 'javassist', module: 'javassist'
|
exclude group: 'javassist', module: 'javassist'
|
||||||
}
|
}
|
||||||
|
compile project(':node-api')
|
||||||
|
|
||||||
compile "com.google.code.findbugs:jsr305:3.0.1"
|
compile "com.google.code.findbugs:jsr305:3.0.1"
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.services.messaging
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.composite
|
import net.corda.core.crypto.composite
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
@ -13,7 +14,6 @@ import net.corda.core.seconds
|
|||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
import net.corda.node.internal.Node
|
import net.corda.node.internal.Node
|
||||||
import net.corda.node.services.User
|
import net.corda.node.services.User
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.CLIENTS_PREFIX
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.CLIENTS_PREFIX
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.INTERNAL_PREFIX
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.INTERNAL_PREFIX
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NETWORK_MAP_QUEUE
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NETWORK_MAP_QUEUE
|
||||||
|
@ -8,6 +8,7 @@ import com.google.common.util.concurrent.ListenableFuture
|
|||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
import com.typesafe.config.ConfigRenderOptions
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
@ -18,7 +19,6 @@ import net.corda.core.utilities.loggerFor
|
|||||||
import net.corda.node.services.User
|
import net.corda.node.services.User
|
||||||
import net.corda.node.services.config.ConfigHelper
|
import net.corda.node.services.config.ConfigHelper
|
||||||
import net.corda.node.services.config.FullNodeConfiguration
|
import net.corda.node.services.config.FullNodeConfiguration
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||||
import net.corda.node.services.messaging.CordaRPCClient
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
import net.corda.node.services.messaging.NodeMessagingClient
|
import net.corda.node.services.messaging.NodeMessagingClient
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
package net.corda.node.services.config
|
package net.corda.node.services.config
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigParseOptions
|
import com.typesafe.config.ConfigParseOptions
|
||||||
import com.typesafe.config.ConfigRenderOptions
|
import com.typesafe.config.ConfigRenderOptions
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.copyTo
|
import net.corda.core.copyTo
|
||||||
import net.corda.core.createDirectories
|
import net.corda.core.createDirectories
|
||||||
import net.corda.core.crypto.X509Utilities
|
import net.corda.core.crypto.X509Utilities
|
||||||
@ -15,13 +15,8 @@ import net.corda.core.div
|
|||||||
import net.corda.core.exists
|
import net.corda.core.exists
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.time.Instant
|
|
||||||
import java.time.LocalDate
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
import kotlin.reflect.jvm.javaType
|
|
||||||
|
|
||||||
object ConfigHelper {
|
object ConfigHelper {
|
||||||
private val log = loggerFor<ConfigHelper>()
|
private val log = loggerFor<ConfigHelper>()
|
||||||
@ -46,57 +41,6 @@ object ConfigHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST", "PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
|
||||||
operator fun <T> Config.getValue(receiver: Any, metadata: KProperty<*>): T {
|
|
||||||
if (metadata.returnType.isMarkedNullable && !hasPath(metadata.name)) {
|
|
||||||
return null as T
|
|
||||||
}
|
|
||||||
return when (metadata.returnType.javaType) {
|
|
||||||
String::class.java -> getString(metadata.name) as T
|
|
||||||
Int::class.java -> getInt(metadata.name) as T
|
|
||||||
Integer::class.java -> getInt(metadata.name) as T
|
|
||||||
Long::class.java -> getLong(metadata.name) as T
|
|
||||||
Double::class.java -> getDouble(metadata.name) as T
|
|
||||||
Boolean::class.java -> getBoolean(metadata.name) as T
|
|
||||||
LocalDate::class.java -> LocalDate.parse(getString(metadata.name)) as T
|
|
||||||
Instant::class.java -> Instant.parse(getString(metadata.name)) as T
|
|
||||||
HostAndPort::class.java -> HostAndPort.fromString(getString(metadata.name)) as T
|
|
||||||
Path::class.java -> Paths.get(getString(metadata.name)) as T
|
|
||||||
URL::class.java -> URL(getString(metadata.name)) as T
|
|
||||||
Properties::class.java -> getProperties(metadata.name) as T
|
|
||||||
else -> throw IllegalArgumentException("Unsupported type ${metadata.returnType}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for optional configurations
|
|
||||||
*/
|
|
||||||
class OptionalConfig<out T>(val conf: Config, val lambda: () -> T) {
|
|
||||||
operator fun getValue(receiver: Any, metadata: KProperty<*>): T {
|
|
||||||
return if (conf.hasPath(metadata.name)) conf.getValue(receiver, metadata) else lambda()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> Config.getOrElse(lambda: () -> T): OptionalConfig<T> = OptionalConfig(this, lambda)
|
|
||||||
|
|
||||||
fun Config.getProperties(path: String): Properties {
|
|
||||||
val obj = this.getObject(path)
|
|
||||||
val props = Properties()
|
|
||||||
for ((property, objectValue) in obj.entries) {
|
|
||||||
props.setProperty(property, objectValue.unwrapped().toString())
|
|
||||||
}
|
|
||||||
return props
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
inline fun <reified T : Any> Config.getListOrElse(path: String, default: Config.() -> List<T>): List<T> {
|
|
||||||
return if (hasPath(path)) {
|
|
||||||
(if (T::class == String::class) getStringList(path) else getConfigList(path)) as List<T>
|
|
||||||
} else {
|
|
||||||
this.default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strictly for dev only automatically construct a server certificate/private key signed from
|
* Strictly for dev only automatically construct a server certificate/private key signed from
|
||||||
* the CA certs in Node resources. Then provision KeyStores into certificates folder under node path.
|
* the CA certs in Node resources. Then provision KeyStores into certificates folder under node path.
|
||||||
|
@ -2,6 +2,10 @@ package net.corda.node.services.config
|
|||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
|
import net.corda.config.getListOrElse
|
||||||
|
import net.corda.config.getOrElse
|
||||||
|
import net.corda.config.getValue
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.node.NodeVersionInfo
|
import net.corda.core.node.NodeVersionInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
@ -15,13 +19,6 @@ import java.net.URL
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
interface SSLConfiguration {
|
|
||||||
val keyStorePassword: String
|
|
||||||
val trustStorePassword: String
|
|
||||||
val certificatesDirectory: Path
|
|
||||||
val keyStoreFile: Path get() = certificatesDirectory / "sslkeystore.jks"
|
|
||||||
val trustStoreFile: Path get() = certificatesDirectory / "truststore.jks"
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NodeConfiguration : SSLConfiguration {
|
interface NodeConfiguration : SSLConfiguration {
|
||||||
val baseDirectory: Path
|
val baseDirectory: Path
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.node.services.messaging
|
|||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting
|
import com.google.common.annotations.VisibleForTesting
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.messaging.MessageRecipientGroup
|
import net.corda.core.messaging.MessageRecipientGroup
|
||||||
import net.corda.core.messaging.MessageRecipients
|
import net.corda.core.messaging.MessageRecipients
|
||||||
@ -9,14 +10,6 @@ import net.corda.core.messaging.SingleMessageRecipient
|
|||||||
import net.corda.core.read
|
import net.corda.core.read
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Inbound
|
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound
|
|
||||||
import org.apache.activemq.artemis.api.core.TransportConfiguration
|
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory
|
|
||||||
import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants
|
|
||||||
import java.nio.file.FileSystems
|
|
||||||
import java.nio.file.Path
|
|
||||||
import java.security.KeyStore
|
import java.security.KeyStore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,8 +36,6 @@ abstract class ArtemisMessagingComponent : SingletonSerializeAsToken() {
|
|||||||
const val NOTIFICATIONS_ADDRESS = "${INTERNAL_PREFIX}activemq.notifications"
|
const val NOTIFICATIONS_ADDRESS = "${INTERNAL_PREFIX}activemq.notifications"
|
||||||
const val NETWORK_MAP_QUEUE = "${INTERNAL_PREFIX}networkmap"
|
const val NETWORK_MAP_QUEUE = "${INTERNAL_PREFIX}networkmap"
|
||||||
|
|
||||||
const val VERIFY_PEER_COMMON_NAME = "corda.verifyPeerCommonName"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assuming the passed in target address is actually an ArtemisAddress will extract the host and port of the node. This should
|
* Assuming the passed in target address is actually an ArtemisAddress will extract the host and port of the node. This should
|
||||||
* only be used in unit tests and the internals of the messaging services to keep addressing opaque for the future.
|
* only be used in unit tests and the internals of the messaging services to keep addressing opaque for the future.
|
||||||
@ -111,19 +102,6 @@ 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: SSLConfiguration?
|
abstract val config: SSLConfiguration?
|
||||||
|
|
||||||
// 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
|
|
||||||
// in case we need to use keytool certificates in some demos
|
|
||||||
private val CIPHER_SUITES = listOf(
|
|
||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
||||||
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns nothing if the keystore was opened OK or throws if not. Useful to check the password, as
|
* Returns nothing if the keystore was opened OK or throws if not. Useful to check the password, as
|
||||||
* unfortunately Artemis tends to bury the exception when the password is wrong.
|
* unfortunately Artemis tends to bury the exception when the password is wrong.
|
||||||
@ -137,57 +115,4 @@ abstract class ArtemisMessagingComponent : SingletonSerializeAsToken() {
|
|||||||
KeyStore.getInstance("JKS").load(it, config.trustStorePassword.toCharArray())
|
KeyStore.getInstance("JKS").load(it, config.trustStorePassword.toCharArray())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun tcpTransport(direction: ConnectionDirection, host: String, port: Int, enableSSL: Boolean = true): TransportConfiguration {
|
|
||||||
// Will throw exception if enableSSL = true but config is missing
|
|
||||||
require(config != null || !enableSSL) { "SSL configuration cannot be null when SSL is enabled." }
|
|
||||||
|
|
||||||
val config = config
|
|
||||||
val options = mutableMapOf<String, Any?>(
|
|
||||||
// Basic TCP target details
|
|
||||||
TransportConstants.HOST_PROP_NAME to host,
|
|
||||||
TransportConstants.PORT_PROP_NAME to port,
|
|
||||||
|
|
||||||
// Turn on AMQP support, which needs the protocol jar on the classpath.
|
|
||||||
// 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
|
|
||||||
// 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"
|
|
||||||
)
|
|
||||||
|
|
||||||
if (config != null && enableSSL) {
|
|
||||||
config.keyStoreFile.expectedOnDefaultFileSystem()
|
|
||||||
config.trustStoreFile.expectedOnDefaultFileSystem()
|
|
||||||
val tlsOptions = mapOf<String, Any?>(
|
|
||||||
// Enable TLS transport layer with client certs and restrict to at least SHA256 in handshake
|
|
||||||
// and AES encryption
|
|
||||||
TransportConstants.SSL_ENABLED_PROP_NAME to true,
|
|
||||||
TransportConstants.KEYSTORE_PROVIDER_PROP_NAME to "JKS",
|
|
||||||
TransportConstants.KEYSTORE_PATH_PROP_NAME to config.keyStoreFile,
|
|
||||||
TransportConstants.KEYSTORE_PASSWORD_PROP_NAME to config.keyStorePassword, // TODO proper management of keystores and password
|
|
||||||
TransportConstants.TRUSTSTORE_PROVIDER_PROP_NAME to "JKS",
|
|
||||||
TransportConstants.TRUSTSTORE_PATH_PROP_NAME to config.trustStoreFile,
|
|
||||||
TransportConstants.TRUSTSTORE_PASSWORD_PROP_NAME to config.trustStorePassword,
|
|
||||||
TransportConstants.ENABLED_CIPHER_SUITES_PROP_NAME to CIPHER_SUITES.joinToString(","),
|
|
||||||
TransportConstants.ENABLED_PROTOCOLS_PROP_NAME to "TLSv1.2",
|
|
||||||
TransportConstants.NEED_CLIENT_AUTH_PROP_NAME to true,
|
|
||||||
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() {
|
|
||||||
require(fileSystem == FileSystems.getDefault()) { "Artemis only uses the default file system" }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected sealed class ConnectionDirection {
|
|
||||||
object Inbound : ConnectionDirection()
|
|
||||||
class Outbound(val expectedCommonName: String? = null) : ConnectionDirection()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,15 @@ import net.corda.core.node.services.NetworkMapCache.MapChange
|
|||||||
import net.corda.core.seconds
|
import net.corda.core.seconds
|
||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
|
import net.corda.node.ArtemisTcpTransport
|
||||||
|
import net.corda.node.ConnectionDirection
|
||||||
|
import net.corda.node.expectedOnDefaultFileSystem
|
||||||
import net.corda.node.printBasicNodeInfo
|
import net.corda.node.printBasicNodeInfo
|
||||||
import net.corda.node.services.RPCUserService
|
import net.corda.node.services.RPCUserService
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.CLIENTS_PREFIX
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.CLIENTS_PREFIX
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NODE_USER
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.NODE_USER
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.PEER_USER
|
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.PEER_USER
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Inbound
|
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound
|
|
||||||
import net.corda.node.services.messaging.NodeLoginModule.Companion.NODE_ROLE
|
import net.corda.node.services.messaging.NodeLoginModule.Companion.NODE_ROLE
|
||||||
import net.corda.node.services.messaging.NodeLoginModule.Companion.PEER_ROLE
|
import net.corda.node.services.messaging.NodeLoginModule.Companion.PEER_ROLE
|
||||||
import net.corda.node.services.messaging.NodeLoginModule.Companion.RPC_ROLE
|
import net.corda.node.services.messaging.NodeLoginModule.Companion.RPC_ROLE
|
||||||
@ -151,9 +152,9 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
bindingsDirectory = (artemisDir / "bindings").toString()
|
bindingsDirectory = (artemisDir / "bindings").toString()
|
||||||
journalDirectory = (artemisDir / "journal").toString()
|
journalDirectory = (artemisDir / "journal").toString()
|
||||||
largeMessagesDirectory = (artemisDir / "large-messages").toString()
|
largeMessagesDirectory = (artemisDir / "large-messages").toString()
|
||||||
val acceptors = mutableSetOf(tcpTransport(Inbound, "0.0.0.0", p2pHostPort.port))
|
val acceptors = mutableSetOf(verifyingTcpTransport(ConnectionDirection.Inbound, "0.0.0.0", p2pHostPort.port))
|
||||||
if (rpcHostPort != null) {
|
if (rpcHostPort != null) {
|
||||||
acceptors.add(tcpTransport(Inbound, "0.0.0.0", rpcHostPort.port, enableSSL = false))
|
acceptors.add(verifyingTcpTransport(ConnectionDirection.Inbound, "0.0.0.0", rpcHostPort.port, enableSSL = false))
|
||||||
}
|
}
|
||||||
acceptorConfigurations = acceptors
|
acceptorConfigurations = acceptors
|
||||||
// Enable built in message deduplication. Note we still have to do our own as the delayed commits
|
// Enable built in message deduplication. Note we still have to do our own as the delayed commits
|
||||||
@ -191,8 +192,8 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticated clients connecting to us fall in one of three groups:
|
* Authenticated clients connecting to us fall in one of the following groups:
|
||||||
* 1. The node hosting us and any of its logically connected components. These are given full access to all valid queues.
|
* 1. The node itself. It is given full access to all valid queues.
|
||||||
* 2. Peers on the same network as us. These are only given permission to send to our P2P inbound queue.
|
* 2. Peers on the same network as us. These are only given permission to send to our P2P inbound queue.
|
||||||
* 3. RPC users. These are only given sufficient access to perform RPC with us.
|
* 3. RPC users. These are only given sufficient access to perform RPC with us.
|
||||||
*/
|
*/
|
||||||
@ -327,6 +328,12 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
deployBridge(address.queueName, address.hostAndPort, legalName)
|
deployBridge(address.queueName, address.hostAndPort, legalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun verifyingTcpTransport(direction: ConnectionDirection, host: String, port: Int, enableSSL: Boolean = true) =
|
||||||
|
ArtemisTcpTransport.tcpTransport(direction, HostAndPort.fromParts(host, port), config,
|
||||||
|
enableSSL = enableSSL,
|
||||||
|
connectorFactoryClassName = VerifyingNettyConnectorFactory::class.java.name
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All nodes are expected to have a public facing address called [ArtemisMessagingComponent.P2P_QUEUE] for receiving
|
* All nodes are expected to have a public facing address called [ArtemisMessagingComponent.P2P_QUEUE] for receiving
|
||||||
* messages from other nodes. When we want to send a message to a node we send it to our internal address/queue for it,
|
* messages from other nodes. When we want to send a message to a node we send it to our internal address/queue for it,
|
||||||
@ -334,7 +341,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
|||||||
* P2P address.
|
* P2P address.
|
||||||
*/
|
*/
|
||||||
private fun deployBridge(queueName: String, target: HostAndPort, legalName: String) {
|
private fun deployBridge(queueName: String, target: HostAndPort, legalName: String) {
|
||||||
val tcpTransport = tcpTransport(Outbound(expectedCommonName = legalName), target.hostText, target.port)
|
val tcpTransport = verifyingTcpTransport(ConnectionDirection.Outbound(expectedCommonName = legalName), target.hostText, target.port)
|
||||||
tcpTransport.params[ArtemisMessagingServer::class.java.name] = this
|
tcpTransport.params[ArtemisMessagingServer::class.java.name] = this
|
||||||
// We intentionally overwrite any previous connector config in case the peer legal name changed
|
// We intentionally overwrite any previous connector config in case the peer legal name changed
|
||||||
activeMQServer.configuration.addConnectorConfiguration(target.toString(), tcpTransport)
|
activeMQServer.configuration.addConnectorConfiguration(target.toString(), tcpTransport)
|
||||||
@ -407,7 +414,7 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
|||||||
protocolManager: ClientProtocolManager?) :
|
protocolManager: ClientProtocolManager?) :
|
||||||
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
|
NettyConnector(configuration, handler, listener, closeExecutor, threadPool, scheduledThreadPool, protocolManager) {
|
||||||
private val server = configuration?.get(ArtemisMessagingServer::class.java.name) as? ArtemisMessagingServer
|
private val server = configuration?.get(ArtemisMessagingServer::class.java.name) as? ArtemisMessagingServer
|
||||||
private val expectedCommonName = configuration?.get(ArtemisMessagingComponent.VERIFY_PEER_COMMON_NAME) as? String
|
private val expectedCommonName = configuration?.get(ArtemisTcpTransport.VERIFY_PEER_COMMON_NAME) as? String
|
||||||
|
|
||||||
override fun createConnection(): Connection? {
|
override fun createConnection(): Connection? {
|
||||||
val connection = super.createConnection() as NettyConnection?
|
val connection = super.createConnection() as NettyConnection?
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package net.corda.node.services.messaging
|
package net.corda.node.services.messaging
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.ThreadBox
|
import net.corda.core.ThreadBox
|
||||||
import net.corda.core.logElapsedTime
|
import net.corda.core.logElapsedTime
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.minutes
|
import net.corda.core.minutes
|
||||||
import net.corda.core.seconds
|
import net.corda.core.seconds
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
import net.corda.node.ArtemisTcpTransport.Companion.tcpTransport
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound
|
import net.corda.node.ConnectionDirection
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQException
|
import org.apache.activemq.artemis.api.core.ActiveMQException
|
||||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient
|
import org.apache.activemq.artemis.api.core.client.ActiveMQClient
|
||||||
import org.apache.activemq.artemis.api.core.client.ClientSession
|
import org.apache.activemq.artemis.api.core.client.ClientSession
|
||||||
@ -52,7 +53,7 @@ class CordaRPCClient(val host: HostAndPort, override val config: SSLConfiguratio
|
|||||||
check(!running)
|
check(!running)
|
||||||
log.logElapsedTime("Startup") {
|
log.logElapsedTime("Startup") {
|
||||||
checkStorePasswords()
|
checkStorePasswords()
|
||||||
val serverLocator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport(Outbound(), host.hostText, host.port, enableSSL = config != null)).apply {
|
val serverLocator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport(ConnectionDirection.Outbound(), host, config, enableSSL = config != null)).apply {
|
||||||
// TODO: Put these in config file or make it user configurable?
|
// TODO: Put these in config file or make it user configurable?
|
||||||
threadPoolMaxSize = 1
|
threadPoolMaxSize = 1
|
||||||
confirmationWindowSize = 100000 // a guess
|
confirmationWindowSize = 100000 // a guess
|
||||||
|
@ -12,10 +12,11 @@ import net.corda.core.serialization.opaque
|
|||||||
import net.corda.core.success
|
import net.corda.core.success
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.core.utilities.trace
|
import net.corda.core.utilities.trace
|
||||||
|
import net.corda.node.ArtemisTcpTransport
|
||||||
|
import net.corda.node.ConnectionDirection
|
||||||
import net.corda.node.services.RPCUserService
|
import net.corda.node.services.RPCUserService
|
||||||
import net.corda.node.services.api.MessagingServiceInternal
|
import net.corda.node.services.api.MessagingServiceInternal
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound
|
|
||||||
import net.corda.node.services.statemachine.StateMachineManager
|
import net.corda.node.services.statemachine.StateMachineManager
|
||||||
import net.corda.node.utilities.*
|
import net.corda.node.utilities.*
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQObjectClosedException
|
import org.apache.activemq.artemis.api.core.ActiveMQObjectClosedException
|
||||||
@ -129,7 +130,7 @@ class NodeMessagingClient(override val config: NodeConfiguration,
|
|||||||
|
|
||||||
log.info("Connecting to server: $serverHostPort")
|
log.info("Connecting to server: $serverHostPort")
|
||||||
// TODO Add broker CN to config for host verification in case the embedded broker isn't used
|
// TODO Add broker CN to config for host verification in case the embedded broker isn't used
|
||||||
val tcpTransport = tcpTransport(Outbound(), serverHostPort.hostText, serverHostPort.port)
|
val tcpTransport = ArtemisTcpTransport.tcpTransport(ConnectionDirection.Outbound(), serverHostPort, config)
|
||||||
val locator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport)
|
val locator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport)
|
||||||
clientFactory = locator.createSessionFactory()
|
clientFactory = locator.createSessionFactory()
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken
|
|||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
import net.corda.config.SSLConfiguration
|
||||||
import org.jetbrains.exposed.sql.Database
|
import org.jetbrains.exposed.sql.Database
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
@ -2,6 +2,7 @@ package net.corda.attachmentdemo
|
|||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import joptsimple.OptionParser
|
import joptsimple.OptionParser
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.contracts.TransactionType
|
import net.corda.core.contracts.TransactionType
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
@ -11,7 +12,6 @@ import net.corda.core.messaging.CordaRPCOps
|
|||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.Emoji
|
import net.corda.core.utilities.Emoji
|
||||||
import net.corda.flows.FinalityFlow
|
import net.corda.flows.FinalityFlow
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.messaging.CordaRPCClient
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
import net.corda.testing.ALICE_KEY
|
import net.corda.testing.ALICE_KEY
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
@ -3,6 +3,7 @@ package net.corda.notarydemo
|
|||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.google.common.util.concurrent.Futures
|
import com.google.common.util.concurrent.Futures
|
||||||
import joptsimple.OptionParser
|
import joptsimple.OptionParser
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.getOrThrow
|
import net.corda.core.getOrThrow
|
||||||
@ -10,7 +11,6 @@ import net.corda.core.messaging.CordaRPCOps
|
|||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.flows.NotaryFlow
|
import net.corda.flows.NotaryFlow
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.messaging.CordaRPCClient
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
import net.corda.notarydemo.flows.DummyIssueAndMove
|
import net.corda.notarydemo.flows.DummyIssueAndMove
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
@ -2,10 +2,10 @@ package net.corda.traderdemo
|
|||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import joptsimple.OptionParser
|
import joptsimple.OptionParser
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.messaging.CordaRPCClient
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
@ -4,6 +4,7 @@ rootProject.name = 'corda-project'
|
|||||||
include 'finance'
|
include 'finance'
|
||||||
include 'finance:isolated'
|
include 'finance:isolated'
|
||||||
include 'core'
|
include 'core'
|
||||||
|
include 'node-api'
|
||||||
include 'node-schemas'
|
include 'node-schemas'
|
||||||
include 'node'
|
include 'node'
|
||||||
include 'node:capsule'
|
include 'node:capsule'
|
||||||
|
@ -6,6 +6,7 @@ package net.corda.testing
|
|||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
@ -20,7 +21,6 @@ import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
|||||||
import net.corda.node.internal.AbstractNode
|
import net.corda.node.internal.AbstractNode
|
||||||
import net.corda.node.internal.NetworkMapInfo
|
import net.corda.node.internal.NetworkMapInfo
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
||||||
import net.corda.node.services.statemachine.FlowStateMachineImpl
|
import net.corda.node.services.statemachine.FlowStateMachineImpl
|
||||||
import net.corda.node.utilities.AddOrRemove.ADD
|
import net.corda.node.utilities.AddOrRemove.ADD
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package net.corda.testing.messaging
|
package net.corda.testing.messaging
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
import net.corda.config.SSLConfiguration
|
||||||
|
import net.corda.node.ArtemisTcpTransport
|
||||||
|
import net.corda.node.ConnectionDirection
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound
|
|
||||||
import net.corda.testing.configureTestSSL
|
import net.corda.testing.configureTestSSL
|
||||||
import org.apache.activemq.artemis.api.core.client.*
|
import org.apache.activemq.artemis.api.core.client.*
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ class SimpleMQClient(val target: HostAndPort,
|
|||||||
lateinit var producer: ClientProducer
|
lateinit var producer: ClientProducer
|
||||||
|
|
||||||
fun start(username: String? = null, password: String? = null, enableSSL: Boolean = true) {
|
fun start(username: String? = null, password: String? = null, enableSSL: Boolean = true) {
|
||||||
val tcpTransport = tcpTransport(Outbound(), target.hostText, target.port, enableSSL)
|
val tcpTransport = ArtemisTcpTransport.tcpTransport(ConnectionDirection.Outbound(), target, config, enableSSL = enableSSL)
|
||||||
val locator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport).apply {
|
val locator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport).apply {
|
||||||
isBlockOnNonDurableSend = true
|
isBlockOnNonDurableSend = true
|
||||||
threadPoolMaxSize = 1
|
threadPoolMaxSize = 1
|
||||||
|
@ -1,20 +1,13 @@
|
|||||||
package net.corda.explorer.views
|
package net.corda.explorer.views
|
||||||
|
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
|
|
||||||
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView
|
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import javafx.scene.control.*
|
import javafx.scene.control.*
|
||||||
import javafx.stage.FileChooser
|
|
||||||
import net.corda.client.fxutils.map
|
|
||||||
import net.corda.client.model.NodeMonitorModel
|
import net.corda.client.model.NodeMonitorModel
|
||||||
import net.corda.client.model.objectProperty
|
import net.corda.client.model.objectProperty
|
||||||
import net.corda.explorer.model.SettingsModel
|
import net.corda.explorer.model.SettingsModel
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
|
||||||
import org.controlsfx.dialog.ExceptionDialog
|
import org.controlsfx.dialog.ExceptionDialog
|
||||||
import tornadofx.*
|
import tornadofx.View
|
||||||
import java.nio.file.Path
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
class LoginView : View() {
|
class LoginView : View() {
|
||||||
|
@ -11,7 +11,7 @@ import net.corda.core.createDirectories
|
|||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.node.driver.PortAllocation
|
import net.corda.node.driver.PortAllocation
|
||||||
import net.corda.node.services.config.SSLConfiguration
|
import net.corda.config.SSLConfiguration
|
||||||
import net.corda.node.services.messaging.CordaRPCClient
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.loadtest
|
package net.corda.loadtest
|
||||||
|
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
|
import net.corda.config.getValue
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import net.corda.node.services.config.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param sshUser The UNIX username to use for SSH auth.
|
* @param sshUser The UNIX username to use for SSH auth.
|
||||||
|
Loading…
Reference in New Issue
Block a user