Merged in pat-move-certificate-path-to-config (pull request #374)

Moved certificates path to node configuration
This commit is contained in:
Patrick Kuo 2016-09-22 15:00:59 +01:00
commit e2c793df05
19 changed files with 132 additions and 130 deletions

View File

@ -24,11 +24,12 @@ import kotlin.concurrent.thread
* useful tasks. See the documentation for [proxy] or review the docsite to learn more about how this API works.
*/
@ThreadSafe
class CordaRPCClient(val host: HostAndPort, certificatesPath: Path) : Closeable, ArtemisMessagingComponent(certificatesPath, sslConfig()) {
class CordaRPCClient(val host: HostAndPort, certificatesPath: Path) : Closeable, ArtemisMessagingComponent(sslConfig(certificatesPath)) {
companion object {
private val rpcLog = LoggerFactory.getLogger("com.r3corda.rpc")
private fun sslConfig(): NodeSSLConfiguration = object : NodeSSLConfiguration {
private fun sslConfig(certificatesPath: Path): NodeSSLConfiguration = object : NodeSSLConfiguration {
override val certificatesPath: Path = certificatesPath
override val keyStorePassword = "cordacadevpass"
override val trustStorePassword = "trustpass"
}

View File

@ -10,9 +10,9 @@ import com.r3corda.core.node.services.ServiceType
import com.r3corda.node.services.config.FullNodeConfiguration
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.config.NodeConfigurationFromConfig
import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.messaging.ArtemisMessagingComponent
import com.r3corda.node.services.messaging.ArtemisMessagingServer
import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.network.InMemoryNetworkMapCache
import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.services.transactions.NotaryService
@ -335,9 +335,7 @@ class DriverDSL(
)
)
)
val client = NodeMessagingClient(
Paths.get(baseDirectory, providedName),
nodeConfiguration,
val client = NodeMessagingClient(nodeConfiguration,
serverHostPort = serverAddress,
myIdentity = identity.public,
executor = AffinityExecutor.ServiceAffinityExecutor(providedName, 1),
@ -366,9 +364,7 @@ class DriverDSL(
)
)
)
val server = ArtemisMessagingServer(
Paths.get(baseDirectory, name),
config,
val server = ArtemisMessagingServer(config,
portAllocation.nextHostAndPort(),
networkMapCache
)

View File

@ -66,7 +66,7 @@ import java.util.concurrent.TimeUnit
// TODO: Where this node is the initial network map service, currently no networkMapService is provided.
// In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the
// AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in.
abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration, val networkMapService: SingleMessageRecipient?,
abstract class AbstractNode(val configuration: NodeConfiguration, val networkMapService: SingleMessageRecipient?,
val advertisedServices: Set<ServiceType>, val platformClock: Clock): SingletonSerializeAsToken() {
companion object {
val PRIVATE_KEY_FILE_NAME = "identity-private-key"
@ -162,7 +162,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
// Do all of this in a database transaction so anything that might need a connection has one.
initialiseDatabasePersistence() {
val storageServices = initialiseStorageService(dir)
val storageServices = initialiseStorageService(configuration.basedir)
storage = storageServices.first
checkpointStorage = storageServices.second
netMapCache = InMemoryNetworkMapCache()
@ -453,8 +453,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
}
protected fun createNodeDir() {
if (!Files.exists(dir)) {
Files.createDirectories(dir)
if (!Files.exists(configuration.basedir)) {
Files.createDirectories(configuration.basedir)
}
}
}

View File

@ -10,8 +10,8 @@ import com.r3corda.node.serialization.NodeClock
import com.r3corda.node.services.api.MessagingServiceInternal
import com.r3corda.node.services.config.FullNodeConfiguration
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.messaging.ArtemisMessagingServer
import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.transactions.PersistentUniquenessProvider
import com.r3corda.node.servlets.AttachmentDownloadServlet
import com.r3corda.node.servlets.Config
@ -38,7 +38,6 @@ import java.time.Clock
import java.util.*
import javax.management.ObjectName
import javax.servlet.*
import javax.servlet.http.HttpServletResponse
import kotlin.concurrent.thread
class ConfigurationException(message: String) : Exception(message)
@ -58,10 +57,10 @@ class ConfigurationException(message: String) : Exception(message)
* @param clock The clock used within the node and by all protocols etc.
* @param messagingServerAddr The address of the Artemis broker instance. If not provided the node will run one locally.
*/
class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
class Node(val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
configuration: NodeConfiguration, networkMapAddress: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, clock: Clock = NodeClock(),
val messagingServerAddr: HostAndPort? = null) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) {
val messagingServerAddr: HostAndPort? = null) : AbstractNode(configuration, networkMapAddress, advertisedServices, clock) {
companion object {
/** The port that is used by default if none is specified. As you know, 31337 is the most elite number. */
@JvmField
@ -120,14 +119,14 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
override fun makeMessagingService(): MessagingServiceInternal {
val serverAddr = messagingServerAddr ?: {
messageBroker = ArtemisMessagingServer(dir, configuration, p2pAddr, services.networkMapCache)
messageBroker = ArtemisMessagingServer(configuration, p2pAddr, services.networkMapCache)
p2pAddr
}()
val ops = ServerRPCOps(services)
if (networkMapService != null) {
return NodeMessagingClient(dir, configuration, serverAddr, services.storageService.myLegalIdentityKey.public, serverThread, rpcOps = ops)
return NodeMessagingClient(configuration, serverAddr, services.storageService.myLegalIdentityKey.public, serverThread, rpcOps = ops)
} else {
return NodeMessagingClient(dir, configuration, serverAddr, null, serverThread, rpcOps = ops)
return NodeMessagingClient(configuration, serverAddr, null, serverThread, rpcOps = ops)
}
}
@ -172,12 +171,10 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
httpsConfiguration.outputBufferSize = 32768
httpsConfiguration.addCustomizer(SecureRequestCustomizer())
val sslContextFactory = SslContextFactory()
val keyStorePath = dir.resolve("certificates").resolve("sslkeystore.jks")
val trustStorePath = dir.resolve("certificates").resolve("truststore.jks")
sslContextFactory.setKeyStorePath(keyStorePath.toString())
sslContextFactory.setKeyStorePath(configuration.keyStorePath.toString())
sslContextFactory.setKeyStorePassword(configuration.keyStorePassword)
sslContextFactory.setKeyManagerPassword(configuration.keyStorePassword)
sslContextFactory.setTrustStorePath(trustStorePath.toString())
sslContextFactory.setTrustStorePath(configuration.trustStorePath.toString())
sslContextFactory.setTrustStorePassword(configuration.trustStorePassword)
sslContextFactory.setExcludeProtocols("SSL.*", "TLSv1", "TLSv1.1")
sslContextFactory.setIncludeProtocols("TLSv1.2")
@ -316,7 +313,7 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
// file that we'll do our best to delete on exit. But if we don't, it'll be overwritten next time. If it already
// exists, we try to take the file lock first before replacing it and if that fails it means we're being started
// twice with the same directory: that's a user error and we should bail out.
val pidPath = dir.resolve("process-id")
val pidPath = configuration.basedir.resolve("process-id")
val file = pidPath.toFile()
if (!file.exists()) {
file.createNewFile()
@ -325,7 +322,7 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
val f = RandomAccessFile(file, "rw")
val l = f.channel.tryLock()
if (l == null) {
log.error("It appears there is already a node running with the specified data directory $dir")
log.error("It appears there is already a node running with the specified data directory ${configuration.basedir}")
log.error("Shut that other node down and try again. It may have process ID ${file.readText()}")
System.exit(1)
}

View File

@ -1,6 +1,7 @@
package com.r3corda.node.services.config
import com.google.common.net.HostAndPort
import com.r3corda.core.div
import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.services.ServiceType
import com.r3corda.node.internal.Node
@ -25,11 +26,14 @@ import kotlin.reflect.jvm.javaType
interface NodeSSLConfiguration {
val keyStorePassword: String
val trustStorePassword: String
// TODO: Move cert paths into this interface as well.
val certificatesPath: Path
val keyStorePath: Path get() = certificatesPath / "sslkeystore.jks"
val trustStorePath: Path get() = certificatesPath / "truststore.jks"
}
interface NodeConfiguration : NodeSSLConfiguration {
val basedir: Path
override val certificatesPath: Path get() = basedir / "certificates"
val myLegalName: String
val nearestCity: String
val emailAddress: String
@ -100,6 +104,7 @@ fun Config.getProperties(path: String): Properties {
}
class NodeConfigurationFromConfig(val config: Config = ConfigFactory.load()) : NodeConfiguration {
override val basedir: Path by config
override val myLegalName: String by config
override val nearestCity: String by config
override val emailAddress: String by config
@ -112,7 +117,7 @@ class NodeConfigurationFromConfig(val config: Config = ConfigFactory.load()) : N
}
class FullNodeConfiguration(conf: Config) : NodeConfiguration {
val basedir: Path by conf
override val basedir: Path by conf
override val myLegalName: String by conf
override val nearestCity: String by conf
override val emailAddress: String by conf
@ -141,8 +146,7 @@ class FullNodeConfiguration(conf: Config) : NodeConfiguration {
}
if (networkMapAddress == null) advertisedServices.add(NetworkMapService.Type)
val networkMapMessageAddress: SingleMessageRecipient? = if (networkMapAddress == null) null else NodeMessagingClient.makeNetworkMapAddress(networkMapAddress)
return Node(basedir.toAbsolutePath().normalize(),
artemisAddress,
return Node(artemisAddress,
webAddress,
this,
networkMapMessageAddress,

View File

@ -27,9 +27,7 @@ import java.security.PublicKey
* @param certificatePath A place where Artemis can stash its message journal and other files.
* @param config The config object is used to pass in the passwords for the certificate KeyStore and TrustStore
*/
abstract class ArtemisMessagingComponent(val certificatePath: Path, val config: NodeSSLConfiguration) : SingletonSerializeAsToken() {
val keyStorePath: Path = certificatePath / "sslkeystore.jks"
val trustStorePath: Path = certificatePath / "truststore.jks"
abstract class ArtemisMessagingComponent(val config: NodeSSLConfiguration) : SingletonSerializeAsToken() {
companion object {
init {
@ -116,10 +114,10 @@ abstract class ArtemisMessagingComponent(val certificatePath: Path, val config:
* unfortunately Artemis tends to bury the exception when the password is wrong.
*/
fun checkStorePasswords() {
keyStorePath.use {
config.keyStorePath.use {
KeyStore.getInstance("JKS").load(it, config.keyStorePassword.toCharArray())
}
trustStorePath.use {
config.trustStorePath.use {
KeyStore.getInstance("JKS").load(it, config.trustStorePassword.toCharArray())
}
}
@ -145,10 +143,10 @@ abstract class ArtemisMessagingComponent(val certificatePath: Path, val config:
// and AES encryption
TransportConstants.SSL_ENABLED_PROP_NAME to true,
TransportConstants.KEYSTORE_PROVIDER_PROP_NAME to "JKS",
TransportConstants.KEYSTORE_PATH_PROP_NAME to keyStorePath,
TransportConstants.KEYSTORE_PATH_PROP_NAME to config.keyStorePath,
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 trustStorePath,
TransportConstants.TRUSTSTORE_PATH_PROP_NAME to config.trustStorePath,
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",
@ -161,16 +159,16 @@ abstract class ArtemisMessagingComponent(val certificatePath: Path, val config:
* the CA certs in Node resources. Then provision KeyStores into certificates folder under node path.
*/
fun configureWithDevSSLCertificate() {
Files.createDirectories(certificatePath)
if (!Files.exists(trustStorePath)) {
Files.createDirectories(config.certificatesPath)
if (!Files.exists(config.trustStorePath)) {
Files.copy(javaClass.classLoader.getResourceAsStream("com/r3corda/node/internal/certificates/cordatruststore.jks"),
trustStorePath)
config.trustStorePath)
}
if (!Files.exists(keyStorePath)) {
if (!Files.exists(config.keyStorePath)) {
val caKeyStore = X509Utilities.loadKeyStore(
javaClass.classLoader.getResourceAsStream("com/r3corda/node/internal/certificates/cordadevcakeys.jks"),
"cordacadevpass")
X509Utilities.createKeystoreForSSL(keyStorePath, config.keyStorePassword, config.keyStorePassword, caKeyStore, "cordacadevkeypass")
X509Utilities.createKeystoreForSSL(config.keyStorePath, config.keyStorePassword, config.keyStorePassword, caKeyStore, "cordacadevkeypass")
}
}
}

View File

@ -4,9 +4,7 @@ import com.google.common.net.HostAndPort
import com.r3corda.core.ThreadBox
import com.r3corda.core.crypto.AddressFormatException
import com.r3corda.core.crypto.newSecureRandom
import com.r3corda.core.div
import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.NetworkMapCache
import com.r3corda.core.utilities.loggerFor
import com.r3corda.node.services.config.NodeConfiguration
@ -39,10 +37,9 @@ import javax.annotation.concurrent.ThreadSafe
* a fully connected network, trusted network or on localhost.
*/
@ThreadSafe
class ArtemisMessagingServer(directory: Path,
config: NodeConfiguration,
class ArtemisMessagingServer(config: NodeConfiguration,
val myHostPort: HostAndPort,
val networkMapCache: NetworkMapCache) : ArtemisMessagingComponent(directory / "certificates", config) {
val networkMapCache: NetworkMapCache) : ArtemisMessagingComponent(config) {
companion object {
val log = loggerFor<ArtemisMessagingServer>()
}
@ -119,7 +116,7 @@ class ArtemisMessagingServer(directory: Path,
}
private fun configureAndStartServer() {
val config = createArtemisConfig(certificatePath, myHostPort).apply {
val config = createArtemisConfig(config.certificatesPath, myHostPort).apply {
securityRoles = mapOf(
"#" to setOf(Role("internal", true, true, true, true, true, true, true))
)

View File

@ -2,7 +2,6 @@ package com.r3corda.node.services.messaging
import com.google.common.net.HostAndPort
import com.r3corda.core.ThreadBox
import com.r3corda.core.div
import com.r3corda.core.messaging.*
import com.r3corda.core.serialization.SerializedBytes
import com.r3corda.core.serialization.opaque
@ -15,7 +14,6 @@ import org.apache.activemq.artemis.api.core.ActiveMQObjectClosedException
import org.apache.activemq.artemis.api.core.SimpleString
import org.apache.activemq.artemis.api.core.client.*
import java.nio.file.FileSystems
import java.nio.file.Path
import java.security.PublicKey
import java.time.Instant
import java.util.concurrent.CopyOnWriteArrayList
@ -46,14 +44,12 @@ import javax.annotation.concurrent.ThreadSafe
* If false the inbox queue will be transient, which is appropriate for UI clients for example.
*/
@ThreadSafe
class NodeMessagingClient(directory: Path,
config: NodeConfiguration,
class NodeMessagingClient(config: NodeConfiguration,
val serverHostPort: HostAndPort,
val myIdentity: PublicKey?,
val executor: AffinityExecutor,
val persistentInbox: Boolean = true,
private val rpcOps: CordaRPCOps? = null)
: ArtemisMessagingComponent(directory / "certificates", config), MessagingServiceInternal {
private val rpcOps: CordaRPCOps? = null) : ArtemisMessagingComponent(config), MessagingServiceInternal {
companion object {
val log = loggerFor<NodeMessagingClient>()
@ -103,7 +99,7 @@ class NodeMessagingClient(directory: Path,
private val handlers = CopyOnWriteArrayList<Handler>()
init {
require(directory.fileSystem == FileSystems.getDefault()) { "Artemis only uses the default file system" }
require(config.basedir.fileSystem == FileSystems.getDefault()) { "Artemis only uses the default file system" }
}
fun start() {

View File

@ -11,10 +11,8 @@ import com.r3corda.core.minutes
import com.r3corda.core.utilities.loggerFor
import com.r3corda.node.services.config.FullNodeConfiguration
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.messaging.ArtemisMessagingComponent
import joptsimple.OptionParser
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.security.KeyPair
import java.security.cert.Certificate
@ -26,23 +24,25 @@ import kotlin.system.exitProcess
* This process will enter a slow polling loop until the request has been approved, and then
* the certificate chain will be downloaded and stored in [KeyStore] reside in [certificatePath].
*/
class CertificateSigner(certificatePath: Path, val nodeConfig: NodeConfiguration, val certService: CertificateSigningService) : ArtemisMessagingComponent(certificatePath, nodeConfig) {
class CertificateSigner(val config: NodeConfiguration, val certService: CertificateSigningService) {
companion object {
val pollInterval = 1.minutes
val log = loggerFor<CertificateSigner>()
}
fun buildKeyStore() {
val caKeyStore = X509Utilities.loadOrCreateKeyStore(keyStorePath, config.keyStorePassword)
Files.createDirectories(config.certificatesPath)
val caKeyStore = X509Utilities.loadOrCreateKeyStore(config.keyStorePath, config.keyStorePassword)
if (!caKeyStore.containsAlias(CORDA_CLIENT_CA)) {
// No certificate found in key store, create certificate signing request and post request to signing server.
log.info("No certificate found in key store, creating certificate signing request...")
// Create or load key pair from the key store.
val keyPair = X509Utilities.loadOrCreateKeyPairFromKeyStore(keyStorePath, config.keyStorePassword,
val keyPair = X509Utilities.loadOrCreateKeyPairFromKeyStore(config.keyStorePath, config.keyStorePassword,
config.keyStorePassword, CORDA_CLIENT_CA_PRIVATE_KEY) {
X509Utilities.createSelfSignedCACert(nodeConfig.myLegalName)
X509Utilities.createSelfSignedCACert(config.myLegalName)
}
log.info("Submitting certificate signing request to Corda certificate signing server.")
val requestId = submitCertificateSigningRequest(keyPair)
@ -58,15 +58,15 @@ class CertificateSigner(certificatePath: Path, val nodeConfig: NodeConfiguration
// Assumes certificate chain always starts with client certificate and end with root certificate.
caKeyStore.addOrReplaceCertificate(CORDA_CLIENT_CA, certificates.first())
X509Utilities.saveKeyStore(caKeyStore, keyStorePath, config.keyStorePassword)
X509Utilities.saveKeyStore(caKeyStore, config.keyStorePath, config.keyStorePassword)
// Save certificates to trust store.
val trustStore = X509Utilities.loadOrCreateKeyStore(trustStorePath, config.trustStorePassword)
val trustStore = X509Utilities.loadOrCreateKeyStore(config.trustStorePath, config.trustStorePassword)
// Assumes certificate chain always starts with client certificate and end with root certificate.
trustStore.addOrReplaceCertificate(CORDA_ROOT_CA, certificates.last())
X509Utilities.saveKeyStore(trustStore, trustStorePath, config.trustStorePassword)
X509Utilities.saveKeyStore(trustStore, config.trustStorePath, config.trustStorePassword)
} else {
log.trace("Certificate already exists, exiting certificate signer...")
}
@ -96,10 +96,10 @@ class CertificateSigner(certificatePath: Path, val nodeConfig: NodeConfiguration
* @return Request ID return from the server.
*/
private fun submitCertificateSigningRequest(keyPair: KeyPair): String {
val requestIdStore = certificatePath / "certificate-request-id.txt"
val requestIdStore = config.certificatesPath / "certificate-request-id.txt"
// Retrieve request id from file if exists, else post a request to server.
return if (!Files.exists(requestIdStore)) {
val request = X509Utilities.createCertificateSigningRequest(nodeConfig.myLegalName, nodeConfig.nearestCity, nodeConfig.emailAddress, keyPair)
val request = X509Utilities.createCertificateSigningRequest(config.myLegalName, config.nearestCity, config.emailAddress, keyPair)
// Post request to signing server via http.
val requestId = certService.submitRequest(request)
// Persists request ID to file in case of node shutdown.
@ -128,6 +128,6 @@ fun main(args: Array<String>) {
val configFile = if (cmdlineOptions.has(ParamsSpec.configFileArg)) Paths.get(cmdlineOptions.valueOf(ParamsSpec.configFileArg)) else null
val conf = FullNodeConfiguration(NodeConfiguration.loadConfig(baseDirectoryPath, configFile, allowMissingConfig = true))
// TODO: Use HTTPS instead
CertificateSigner(baseDirectoryPath / "certificate", conf, HTTPCertificateSigningService(conf.certificateSigningService)).buildKeyStore()
CertificateSigner(conf, HTTPCertificateSigningService(conf.certificateSigningService)).buildKeyStore()
}

View File

@ -88,9 +88,9 @@ class AttachmentTests {
fun `malicious response`() {
// Make a node that doesn't do sanity checking at load time.
val n0 = network.createNode(null, -1, object : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
return object : MockNetwork.MockNode(dir, config, network, networkMapAddr, advertisedServices, id, keyPair) {
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) {
override fun start(): MockNetwork.MockNode {
super.start()
(storage.attachments as NodeAttachmentService).checkAttachmentsOnLoad = false

View File

@ -154,9 +154,9 @@ class TwoPartyTradeProtocolTests {
// ... bring the node back up ... the act of constructing the SMM will re-register the message handlers
// that Bob was waiting on before the reboot occurred.
bobNode = net.createNode(networkMapAddr, bobAddr.id, object : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
return MockNetwork.MockNode(dir, config, network, networkMapAddr, advertisedServices, bobAddr.id, BOB_KEY)
return MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, bobAddr.id, BOB_KEY)
}
}, true, BOB.name, BOB_KEY)
@ -184,9 +184,9 @@ class TwoPartyTradeProtocolTests {
private fun makeNodeWithTracking(networkMapAddr: SingleMessageRecipient?, name: String, keyPair: KeyPair): MockNetwork.MockNode {
// Create a node in the mock network ...
return net.createNode(networkMapAddr, -1, object : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
return object : MockNetwork.MockNode(dir, config, network, networkMapAddr, advertisedServices, id, keyPair) {
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) {
// That constructs the storage service object in a customised way ...
override fun constructStorageService(attachments: NodeAttachmentService,
transactionStorage: TransactionStorage,

View File

@ -5,17 +5,19 @@ import com.r3corda.core.crypto.generateKeyPair
import com.r3corda.core.messaging.Message
import com.r3corda.core.node.services.DEFAULT_SESSION_ID
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.messaging.ArtemisMessagingServer
import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.network.InMemoryNetworkMapCache
import com.r3corda.node.utilities.AffinityExecutor
import com.r3corda.testing.freeLocalHostAndPort
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.net.ServerSocket
import java.nio.file.Path
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit.MILLISECONDS
import kotlin.concurrent.thread
@ -29,25 +31,30 @@ class ArtemisMessagingTests {
val topic = "platform.self"
val identity = generateKeyPair()
// TODO: create a base class that provides a default implementation
val config = object : NodeConfiguration {
override val myLegalName: String = "me"
override val nearestCity: String = "London"
override val emailAddress: String = ""
override val devMode: Boolean = true
override val exportJMXto: String = ""
override val keyStorePassword: String = "testpass"
override val trustStorePassword: String = "trustpass"
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
lateinit var config: NodeConfiguration
var messagingClient: NodeMessagingClient? = null
var messagingServer: ArtemisMessagingServer? = null
val networkMapCache = InMemoryNetworkMapCache()
@Before
fun setUp() {
// TODO: create a base class that provides a default implementation
config = object : NodeConfiguration {
override val basedir: Path = temporaryFolder.newFolder().toPath()
override val myLegalName: String = "me"
override val nearestCity: String = "London"
override val emailAddress: String = ""
override val devMode: Boolean = true
override val exportJMXto: String = ""
override val keyStorePassword: String = "testpass"
override val trustStorePassword: String = "trustpass"
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
}
@After
fun cleanUp() {
messagingClient?.stop()
@ -111,14 +118,14 @@ class ArtemisMessagingTests {
}
private fun createMessagingClient(server: HostAndPort = hostAndPort): NodeMessagingClient {
return NodeMessagingClient(temporaryFolder.newFolder().toPath(), config, server, identity.public, AffinityExecutor.SAME_THREAD).apply {
return NodeMessagingClient(config, server, identity.public, AffinityExecutor.SAME_THREAD).apply {
configureWithDevSSLCertificate()
messagingClient = this
}
}
private fun createMessagingServer(local: HostAndPort = hostAndPort): ArtemisMessagingServer {
return ArtemisMessagingServer(temporaryFolder.newFolder().toPath(), config, local, networkMapCache).apply {
return ArtemisMessagingServer(config, local, networkMapCache).apply {
configureWithDevSSLCertificate()
messagingServer = this
}

View File

@ -59,9 +59,9 @@ class PersistentNetworkMapServiceTest : AbstractNetworkMapServiceTest() {
}
private object NodeFactory : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
return object : MockNetwork.MockNode(dir, config, network, networkMapAddr, advertisedServices, id, keyPair) {
return object : MockNetwork.MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair) {
override fun makeNetworkMapService() {
inNodeNetworkMapService = SwizzleNetworkMapService(services)

View File

@ -12,6 +12,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.nio.file.Files
import java.nio.file.Path
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -35,13 +36,9 @@ class CertificateSignerTest {
on { retrieveCertificates(eq(id)) }.then { certs }
}
val keyStore = tempFolder.root.toPath().resolve("sslkeystore.jks")
val tmpTrustStore = tempFolder.root.toPath().resolve("truststore.jks")
assertFalse(Files.exists(keyStore))
assertFalse(Files.exists(tmpTrustStore))
val config = object : NodeConfiguration {
override val basedir: Path = tempFolder.root.toPath()
override val myLegalName: String = "me"
override val nearestCity: String = "London"
override val emailAddress: String = ""
@ -52,12 +49,15 @@ class CertificateSignerTest {
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
CertificateSigner(tempFolder.root.toPath(), config, certService).buildKeyStore()
assertFalse(Files.exists(config.keyStorePath))
assertFalse(Files.exists(config.trustStorePath))
assertTrue(Files.exists(keyStore))
assertTrue(Files.exists(tmpTrustStore))
CertificateSigner(config, certService).buildKeyStore()
X509Utilities.loadKeyStore(keyStore, config.keyStorePassword).run {
assertTrue(Files.exists(config.keyStorePath))
assertTrue(Files.exists(config.trustStorePath))
X509Utilities.loadKeyStore(config.keyStorePath, config.keyStorePassword).run {
assertTrue(containsAlias(X509Utilities.CORDA_CLIENT_CA_PRIVATE_KEY))
assertTrue(containsAlias(X509Utilities.CORDA_CLIENT_CA))
assertFalse(containsAlias(X509Utilities.CORDA_INTERMEDIATE_CA))
@ -66,7 +66,7 @@ class CertificateSignerTest {
assertFalse(containsAlias(X509Utilities.CORDA_ROOT_CA_PRIVATE_KEY))
}
X509Utilities.loadKeyStore(tmpTrustStore, config.trustStorePassword).run {
X509Utilities.loadKeyStore(config.trustStorePath, config.trustStorePassword).run {
assertFalse(containsAlias(X509Utilities.CORDA_CLIENT_CA_PRIVATE_KEY))
assertFalse(containsAlias(X509Utilities.CORDA_CLIENT_CA))
assertFalse(containsAlias(X509Utilities.CORDA_INTERMEDIATE_CA))
@ -75,7 +75,7 @@ class CertificateSignerTest {
assertFalse(containsAlias(X509Utilities.CORDA_ROOT_CA_PRIVATE_KEY))
}
assertEquals(id, Files.readAllLines(tempFolder.root.toPath() / "certificate-request-id.txt").first())
assertEquals(id, Files.readAllLines(config.certificatesPath / "certificate-request-id.txt").first())
}
}

View File

@ -321,7 +321,7 @@ private fun setup(params: CliParams.SetupNode): Int {
val configFile = params.dir.resolve("config")
val config = loadConfigFile(params.dir, configFile, params.defaultLegalName)
if (!Files.exists(params.dir.resolve(AbstractNode.PUBLIC_IDENTITY_FILE_NAME))) {
createIdentities(params, config)
createIdentities(config)
}
return 0
}
@ -407,7 +407,7 @@ private fun startNode(params: CliParams.RunNode, networkMap: SingleMessageRecipi
}
val node = logElapsedTime("Node startup", log) {
Node(params.dir, params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock()).setup().start()
Node(params.networkAddress, params.apiAddress, config, networkMapId, advertisedServices, DemoClock()).setup().start()
}
return node
@ -459,9 +459,9 @@ private fun loadConfigFile(baseDir: Path, configFile: Path, defaultLegalName: St
return NodeConfigurationFromConfig(NodeConfiguration.loadConfig(baseDir, configFileOverride = configFile))
}
private fun createIdentities(params: CliParams.SetupNode, nodeConf: NodeConfiguration) {
private fun createIdentities(nodeConf: NodeConfiguration) {
val mockNetwork = MockNetwork(false)
val node = MockNetwork.MockNode(params.dir, nodeConf, mockNetwork, null, setOf(NetworkMapService.Type, SimpleNotaryService.Type), 0, null)
val node = MockNetwork.MockNode(nodeConf, mockNetwork, null, setOf(NetworkMapService.Type, SimpleNotaryService.Type), 0, null)
node.start()
node.stop()
}

View File

@ -18,6 +18,7 @@ import joptsimple.OptionParser
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.math.BigDecimal
import java.nio.file.Path
import java.nio.file.Paths
import java.util.*
import kotlin.system.exitProcess
@ -61,7 +62,7 @@ fun main(args: Array<String>) {
// TODO: create a base class that provides a default implementation
val config = object : NodeConfiguration {
override val basedir: Path = dir
override val myLegalName: String = "Rate fix demo node"
override val nearestCity: String = "Atlantis"
override val emailAddress: String = ""
@ -76,7 +77,7 @@ fun main(args: Array<String>) {
val apiAddr = HostAndPort.fromParts(myNetAddr.hostText, myNetAddr.port + 1)
val node = logElapsedTime("Node startup") { Node(dir, myNetAddr, apiAddr, config, networkMapAddr,
val node = logElapsedTime("Node startup") { Node(myNetAddr, apiAddr, config, networkMapAddr,
advertisedServices, DemoClock()).setup().start() }
node.networkMapRegistrationFuture.get()
val notaryNode = node.services.networkMapCache.notaryNodes[0]

View File

@ -140,7 +140,7 @@ fun main(args: Array<String>) {
// And now construct then start the node object. It takes a little while.
val node = logElapsedTime("Node startup", log) {
Node(directory, myNetAddr, apiNetAddr, config, networkMapId, advertisedServices).setup().start()
Node(myNetAddr, apiNetAddr, config, networkMapId, advertisedServices).setup().start()
}
// What happens next depends on the role. The buyer sits around waiting for a trade to start. The seller role

View File

@ -45,22 +45,22 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
// This puts together a mock network of SimulatedNodes.
open class SimulatedNode(dir: Path, config: NodeConfiguration, mockNet: MockNetwork, networkMapAddress: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?) : MockNetwork.MockNode(dir, config, mockNet, networkMapAddress, advertisedServices, id, keyPair) {
open class SimulatedNode(config: NodeConfiguration, mockNet: MockNetwork, networkMapAddress: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?) : MockNetwork.MockNode(config, mockNet, networkMapAddress, advertisedServices, id, keyPair) {
override fun findMyLocation(): PhysicalLocation? = CityDatabase[configuration.nearestCity]
}
inner class BankFactory : MockNetwork.Factory {
var counter = 0
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
val letter = 'A' + counter
val city = bankLocations[counter++ % bankLocations.size]
// TODO: create a base class that provides a default implementation
val cfg = object : NodeConfiguration {
override val basedir: Path = config.basedir
// TODO: Set this back to "Bank of $city" after video day.
override val myLegalName: String = "Bank $letter"
override val nearestCity: String = city
@ -71,7 +71,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
override val trustStorePassword: String = "trustpass"
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
return SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair)
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair)
}
fun createAll(): List<SimulatedNode> = bankLocations.
@ -81,12 +81,13 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
val bankFactory = BankFactory()
object NetworkMapNodeFactory : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork,
override fun create(config: NodeConfiguration, network: MockNetwork,
networkMapAddr: SingleMessageRecipient?, advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
require(advertisedServices.contains(NetworkMapService.Type))
// TODO: create a base class that provides a default implementation
val cfg = object : NodeConfiguration {
override val basedir: Path = config.basedir
override val myLegalName: String = "Network coordination center"
override val nearestCity: String = "Amsterdam"
override val emailAddress: String = ""
@ -97,17 +98,18 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
return object : SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair) {}
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) {}
}
}
object NotaryNodeFactory : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
require(advertisedServices.contains(SimpleNotaryService.Type))
// TODO: create a base class that provides a default implementation
val cfg = object : NodeConfiguration {
override val basedir: Path = config.basedir
override val myLegalName: String = "Notary Service"
override val nearestCity: String = "Zurich"
override val emailAddress: String = ""
@ -117,17 +119,18 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
override val trustStorePassword: String = "trustpass"
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
return SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair)
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair)
}
}
object RatesOracleFactory : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
require(advertisedServices.contains(NodeInterestRates.Type))
// TODO: create a base class that provides a default implementation
val cfg = object : NodeConfiguration {
override val basedir: Path = config.basedir
override val myLegalName: String = "Rates Service Provider"
override val nearestCity: String = "Madrid"
override val emailAddress: String = ""
@ -138,7 +141,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
return object : SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair) {
return object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) {
override fun start(): MockNetwork.MockNode {
super.start()
findService<NodeInterestRates.Service>().upload(javaClass.getResourceAsStream("example.rates.txt"))
@ -149,11 +152,12 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
}
object RegulatorFactory : MockNetwork.Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNetwork.MockNode {
// TODO: create a base class that provides a default implementation
val cfg = object : NodeConfiguration {
override val basedir: Path = config.basedir
override val myLegalName: String = "Regulator A"
override val nearestCity: String = "Paris"
override val emailAddress: String = ""
@ -164,7 +168,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
val n = object : SimulatedNode(dir, cfg, network, networkMapAddr, advertisedServices, id, keyPair) {
val n = object : SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) {
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
// So we just fire a message at a node that doesn't know how to handle it, and it'll ignore it.
// But that's fine for visualisation purposes.

View File

@ -18,6 +18,7 @@ import com.r3corda.core.serialization.deserialize
import com.r3corda.core.testing.InMemoryVaultService
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
import com.r3corda.core.utilities.loggerFor
import com.r3corda.node.internal.AbstractNode
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.keys.E2ETestKeyManagementService
import com.r3corda.node.services.network.InMemoryNetworkMapService
@ -61,19 +62,19 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
/** Allows customisation of how nodes are created. */
interface Factory {
fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNode
}
object DefaultFactory : Factory {
override fun create(dir: Path, config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
override fun create(config: NodeConfiguration, network: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, id: Int, keyPair: KeyPair?): MockNode {
return MockNode(dir, config, network, networkMapAddr, advertisedServices, id, keyPair)
return MockNode(config, network, networkMapAddr, advertisedServices, id, keyPair)
}
}
open class MockNode(dir: Path, config: NodeConfiguration, val mockNet: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, val id: Int, val keyPair: KeyPair?) : com.r3corda.node.internal.AbstractNode(dir, config, networkMapAddr, advertisedServices, TestClock()) {
open class MockNode(config: NodeConfiguration, val mockNet: MockNetwork, networkMapAddr: SingleMessageRecipient?,
advertisedServices: Set<ServiceType>, val id: Int, val keyPair: KeyPair?) : AbstractNode(config, networkMapAddr, advertisedServices, TestClock()) {
override val log: Logger = loggerFor<MockNode>()
override val serverThread: com.r3corda.node.utilities.AffinityExecutor =
if (mockNet.threadPerNode)
@ -167,7 +168,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
// TODO: create a base class that provides a default implementation
val config = object : NodeConfiguration {
override val basedir: Path = path
override val myLegalName: String = legalName ?: "Mock Company $id"
override val nearestCity: String = "Atlantis"
override val emailAddress: String = ""
@ -178,7 +179,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
override val dataSourceProperties: Properties get() = if (databasePersistence) makeTestDataSourceProperties("node_$id") else Properties()
override val certificateSigningService: HostAndPort = HostAndPort.fromParts("localhost", 0)
}
val node = nodeFactory.create(path, config, this, networkMapAddress, advertisedServices.toSet(), id, keyPair)
val node = nodeFactory.create(config, this, networkMapAddress, advertisedServices.toSet(), id, keyPair)
if (start) {
node.setup().start()
if (threadPerNode && networkMapAddress != null)