mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Clean up messaging/RPC port configuration and docs (#296)
* Non-ssl artemis acceptor for RPC connection. (#271) * New non-ssl acceptor in artemis server for RPC connection. * Rename artemisAddress with messagingAddress Rename artemisAddress with messagingAddress so that the node configuration file properties match the code variable names. Rename artemisPort to messagingPort in Gradle configuration to match node configuration naming. * Add rpcPort configuration option for Gradle * Update docs to reflect changes to RPC port configuration * Renumber ports in example CorDapp to match numbering used elsewhere * Restructure upgrade guide * added config file checks on corda startup to make the upgrade path a bit smoother.
This commit is contained in:
parent
eb21458885
commit
486368d926
@ -3,7 +3,7 @@
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="net.corda.attachmentdemo.AttachmentDemoKt" />
|
||||
<option name="VM_PARAMETERS" value="-ea -javaagent:lib/quasar.jar " />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role=RECIPIENT --certificates="build/attachment-demo-nodes/Bank B/certificates"" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role=RECIPIENT" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="net.corda.attachmentdemo.AttachmentDemoKt" />
|
||||
<option name="VM_PARAMETERS" value="-ea -javaagent:lib/quasar.jar " />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role SENDER --certificates="build/attachment-demo-nodes/Bank A/certificates"" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role SENDER" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="net.corda.traderdemo.TraderDemoKt" />
|
||||
<option name="VM_PARAMETERS" value="-ea -javaagent:lib/quasar.jar " />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role BUYER --certificates="build/trader-demo-nodes/Bank A/certificates"" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role BUYER" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="net.corda.traderdemo.TraderDemoKt" />
|
||||
<option name="VM_PARAMETERS" value="-ea -javaagent:lib/quasar.jar " />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role SELLER --certificates="build/trader-demo-nodes/Bank B/certificates"" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--role SELLER" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
|
12
build.gradle
12
build.gradle
@ -163,23 +163,25 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Controller"
|
||||
nearestCity "London"
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
artemisPort 10002
|
||||
p2pPort 10002
|
||||
cordapps = []
|
||||
}
|
||||
node {
|
||||
name "Bank A"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10012
|
||||
rpcPort 10013
|
||||
webPort 10014
|
||||
cordapps = []
|
||||
}
|
||||
node {
|
||||
name "Bank B"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 10006
|
||||
webPort 10007
|
||||
p2pPort 10007
|
||||
rpcPort 10008
|
||||
webPort 10009
|
||||
cordapps = []
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.internal.Node
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.testing.configureTestSSL
|
||||
import net.corda.testing.node.NodeBasedTest
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
@ -37,7 +37,7 @@ class CordaRPCClientTest : NodeBasedTest() {
|
||||
@Before
|
||||
fun setUp() {
|
||||
node = startNode("Alice", rpcUsers = listOf(rpcUser), advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type))).getOrThrow()
|
||||
client = CordaRPCClient(node.configuration.artemisAddress, configureTestSSL())
|
||||
client = CordaRPCClient(node.configuration.rpcAddress!!)
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -25,8 +25,6 @@ import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.driver.DriverBasedTest
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||
import net.corda.node.services.network.NetworkMapService
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
@ -57,9 +55,10 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
||||
)
|
||||
val aliceNodeFuture = startNode("Alice", rpcUsers = listOf(cashUser))
|
||||
val notaryNodeFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
|
||||
|
||||
aliceNode = aliceNodeFuture.getOrThrow().nodeInfo
|
||||
notaryNode = notaryNodeFuture.getOrThrow().nodeInfo
|
||||
val aliceNodeHandle = aliceNodeFuture.getOrThrow()
|
||||
val notaryNodeHandle = notaryNodeFuture.getOrThrow()
|
||||
aliceNode = aliceNodeHandle.nodeInfo
|
||||
notaryNode = notaryNodeHandle.nodeInfo
|
||||
newNode = { nodeName -> startNode(nodeName).getOrThrow().nodeInfo }
|
||||
val monitor = NodeMonitorModel()
|
||||
|
||||
@ -70,7 +69,7 @@ class NodeMonitorModelTest : DriverBasedTest() {
|
||||
vaultUpdates = monitor.vaultUpdates.bufferUntilSubscribed()
|
||||
networkMapUpdates = monitor.networkMap.bufferUntilSubscribed()
|
||||
|
||||
monitor.register(ArtemisMessagingComponent.toHostAndPort(aliceNode.address), configureTestSSL(), cashUser.username, cashUser.password)
|
||||
monitor.register(aliceNodeHandle.configuration.rpcAddress!!, cashUser.username, cashUser.password)
|
||||
rpc = monitor.proxyObservable.value!!
|
||||
runTest()
|
||||
}
|
||||
|
@ -52,8 +52,8 @@ class NodeMonitorModel {
|
||||
* Register for updates to/from a given vault.
|
||||
* TODO provide an unsubscribe mechanism
|
||||
*/
|
||||
fun register(nodeHostAndPort: HostAndPort, sslConfig: SSLConfiguration, username: String, password: String) {
|
||||
val client = CordaRPCClient(nodeHostAndPort, sslConfig){
|
||||
fun register(nodeHostAndPort: HostAndPort, username: String, password: String) {
|
||||
val client = CordaRPCClient(nodeHostAndPort){
|
||||
maxRetryInterval = 10.seconds.toMillis()
|
||||
}
|
||||
client.start(username, password)
|
||||
|
@ -2,11 +2,12 @@ myLegalName : "Bank A"
|
||||
nearestCity : "London"
|
||||
keyStorePassword : "cordacadevpass"
|
||||
trustStorePassword : "trustpass"
|
||||
artemisAddress : "localhost:31337"
|
||||
webAddress : "localhost:31339"
|
||||
p2pAddress : "localhost:10002"
|
||||
rpcAddress : "localhost:10003"
|
||||
webAddress : "localhost:10004"
|
||||
extraAdvertisedServiceIds : [ "corda.interest_rates" ]
|
||||
networkMapService : {
|
||||
address : "localhost:12345"
|
||||
address : "localhost:10000"
|
||||
legalName : "Network Map Service"
|
||||
}
|
||||
useHTTPS : false
|
||||
|
@ -2,11 +2,12 @@ myLegalName : "Bank B"
|
||||
nearestCity : "London"
|
||||
keyStorePassword : "cordacadevpass"
|
||||
trustStorePassword : "trustpass"
|
||||
artemisAddress : "localhost:31338"
|
||||
webAddress : "localhost:31340"
|
||||
p2pAddress : "localhost:10005"
|
||||
rpcAddress : "localhost:10006"
|
||||
webAddress : "localhost:10007"
|
||||
extraAdvertisedServiceIds : [ "corda.interest_rates" ]
|
||||
networkMapService : {
|
||||
address : "localhost:12345"
|
||||
address : "localhost:10000"
|
||||
legalName : "Network Map Service"
|
||||
}
|
||||
useHTTPS : false
|
||||
|
@ -2,7 +2,7 @@ myLegalName : "Notary Service"
|
||||
nearestCity : "London"
|
||||
keyStorePassword : "cordacadevpass"
|
||||
trustStorePassword : "trustpass"
|
||||
artemisAddress : "localhost:12345"
|
||||
webAddress : "localhost:12346"
|
||||
p2pAddress : "localhost:10000"
|
||||
webAddress : "localhost:10001"
|
||||
extraAdvertisedServiceIds : [ "corda.notary.validating" ]
|
||||
useHTTPS : false
|
||||
useHTTPS : false
|
||||
|
@ -14,6 +14,15 @@ API changes:
|
||||
using strings like "1000.00 USD" when writing. You can use any format supported by ``Amount.parseCurrency``
|
||||
as input.
|
||||
|
||||
|
||||
Milestone 10
|
||||
------------
|
||||
|
||||
* Configuration:
|
||||
* Replace ``artemisPort`` with ``p2pPort`` in Gradle configuration
|
||||
* Replace ``artemisAddress`` with ``p2pAddress`` in node configuration
|
||||
* Added ``rpcAddress`` in node configuration
|
||||
|
||||
Milestone 9.1
|
||||
-------------
|
||||
|
||||
|
@ -38,8 +38,9 @@ NetworkMapService plus Simple Notary configuration file.
|
||||
nearestCity : "London"
|
||||
keyStorePassword : "cordacadevpass"
|
||||
trustStorePassword : "trustpass"
|
||||
artemisAddress : "localhost:12345"
|
||||
webAddress : "localhost:12346"
|
||||
p2pAddress : "localhost:12345"
|
||||
rpcAddress : "localhost:12346"
|
||||
webAddress : "localhost:12347"
|
||||
extraAdvertisedServiceIds : []
|
||||
useHTTPS : false
|
||||
devMode : true
|
||||
@ -74,13 +75,15 @@ path to the node's base directory.
|
||||
Currently the defaults in ``/node/src/main/resources/reference.conf`` are as shown in the first example. This is currently
|
||||
the only configuration that has been tested, although in the future full support for other storage layers will be validated.
|
||||
|
||||
:artemisAddress: The host and port on which the node is available for protocol operations over ArtemisMQ.
|
||||
:messagingServerAddress: The address of the ArtemisMQ broker instance. If not provided the node will run one locally.
|
||||
|
||||
:p2pAddress: The host and port on which the node is available for protocol operations over ArtemisMQ.
|
||||
|
||||
.. note:: In practice the ArtemisMQ messaging services bind to all local addresses on the specified port. However,
|
||||
note that the host is the included as the advertised entry in the NetworkMapService. As a result the value listed
|
||||
here must be externally accessible when running nodes across a cluster of machines.
|
||||
|
||||
:messagingServerAddress: The address of the ArtemisMQ broker instance. If not provided the node will run one locally.
|
||||
:rpcAddress: The address of the RPC system on which RPC requests can be made to the node. If not provided then the node will run without RPC.
|
||||
|
||||
:webAddress: The host and port on which the bundled webserver will listen if it is started.
|
||||
|
||||
|
@ -214,24 +214,27 @@ is a three node example;
|
||||
name "Controller"
|
||||
nearestCity "London"
|
||||
advertisedServices = [ "corda.notary.validating" ]
|
||||
artemisPort 12345
|
||||
webPort 12346
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
webPort 10004
|
||||
cordapps []
|
||||
}
|
||||
node {
|
||||
name "NodeA"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 31337
|
||||
webPort 31339
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps []
|
||||
}
|
||||
node {
|
||||
name "NodeB"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 31338
|
||||
webPort 31340
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps []
|
||||
}
|
||||
}
|
||||
|
@ -80,16 +80,18 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Notary"
|
||||
nearestCity "London"
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
artemisPort 10002
|
||||
webPort 10003
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
webPort 10004
|
||||
cordapps = []
|
||||
}
|
||||
node {
|
||||
name "Alice"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
rpcUsers = [
|
||||
['user' : "user",
|
||||
|
@ -2,7 +2,7 @@ myLegalName : "Notary Service"
|
||||
nearestCity : "London"
|
||||
keyStorePassword : "cordacadevpass"
|
||||
trustStorePassword : "trustpass"
|
||||
artemisAddress : "my-network-map:10000"
|
||||
p2pAddress : "my-network-map:10000"
|
||||
webAddress : "localhost:10001"
|
||||
extraAdvertisedServiceIds : []
|
||||
useHTTPS : false
|
||||
|
@ -8,8 +8,9 @@ dataSourceProperties : {
|
||||
"dataSource.user" : sa
|
||||
"dataSource.password" : ""
|
||||
}
|
||||
artemisAddress : "my-corda-node:10002"
|
||||
webAddress : "localhost:10003"
|
||||
p2pAddress : "my-corda-node:10002"
|
||||
rpcAddress : "my-corda-node:10003"
|
||||
webAddress : "localhost:10004"
|
||||
extraAdvertisedServiceIds : [ "corda.interest_rates" ]
|
||||
networkMapService : {
|
||||
address : "my-network-map:10000"
|
||||
@ -21,4 +22,4 @@ rpcUsers : [
|
||||
]
|
||||
devMode : true
|
||||
// Certificate signing service will be hosted by R3 in the near future.
|
||||
//certificateSigningService : "https://testnet.certificate.corda.net"
|
||||
//certificateSigningService : "https://testnet.certificate.corda.net"
|
||||
|
@ -4,6 +4,15 @@ Release notes
|
||||
Here are release notes for each snapshot release from M9 onwards. This includes guidance on how to upgrade code from
|
||||
the previous milestone release.
|
||||
|
||||
Milestone 10
|
||||
------------
|
||||
|
||||
Important: There are configuration changes in M10 due to the split of the Artemis port into separate P2P and RPC
|
||||
ports. To upgrade, you *must*:
|
||||
|
||||
1. In Gradle build configurations replace any references to ``artemisPort`` with ``p2pPort``.
|
||||
2. In node configurations replace ``artemisAddress`` with ``p2pAddress``.
|
||||
|
||||
Milestone 9
|
||||
-----------
|
||||
|
||||
@ -46,4 +55,4 @@ clients.
|
||||
There have also been dozens of bug fixes, performance improvements and usability tweaks. Upgrading is definitely
|
||||
worthwhile and will only take a few minutes for most apps.
|
||||
|
||||
For a full list of changes please see :doc:`change-log`.
|
||||
For a full list of changes please see :doc:`change-log`.
|
||||
|
@ -235,7 +235,7 @@ To run from IntelliJ:
|
||||
4. Run ``Bank Of Corda Demo: Run Web Cash Issue`` to request issuance of some cash on behalf of Big Corporation via HTTP
|
||||
|
||||
.. note:: To verify that the Bank of Corda node is alive and running, navigate to the following URL:
|
||||
http://localhost:10005/api/bank/date
|
||||
http://localhost:10007/api/bank/date
|
||||
|
||||
.. note:: The Bank of Corda node explicitly advertises with a node service type as follows:
|
||||
``advertisedServices = setOf(ServiceInfo(ServiceType.corda.getSubType("issuer"))))``
|
||||
@ -259,8 +259,8 @@ Launch the Explorer application to visualize the issuance and transfer of cash f
|
||||
|
||||
Using the following login details:
|
||||
|
||||
- For the Bank of Corda node: localhost / port 10004 / username bankUser / password test
|
||||
- For the Big Corporation node: localhost / port 10006 / username bigCorpUser / password test
|
||||
- For the Bank of Corda node: localhost / port 10006 / username bankUser / password test
|
||||
- For the Big Corporation node: localhost / port 10009 / username bigCorpUser / password test
|
||||
|
||||
See https://docs.corda.net/node-explorer.html for further details on usage.
|
||||
|
||||
|
@ -42,11 +42,13 @@ An example configuration:
|
||||
|
||||
The most important fields regarding network configuration are:
|
||||
|
||||
* ``artemisAddress``: This specifies a host and port. Note that the address bound will **NOT** be ``my-corda-node``,
|
||||
but rather ``::`` (all addresses on all interfaces). The hostname specified is the hostname *that must be externally
|
||||
resolvable by other nodes in the network*. In the above configuration this is the resolvable name of a machine in a vpn.
|
||||
* ``webAddress``: The address the webserver should bind. Note that the port should be distinct from that of ``artemisAddress``
|
||||
if they are on the same machine.
|
||||
* ``p2pAddress``: This specifies a host and port to which Artemis will bind for messaging with other nodes. Note that the
|
||||
address bound will **NOT** be ``my-corda-node``, but rather ``::`` (all addresses on all network interfaces). The hostname specified
|
||||
is the hostname *that must be externally resolvable by other nodes in the network*. In the above configuration this is the
|
||||
resolvable name of a machine in a VPN.
|
||||
* ``rpcAddress``: The address to which Artemis will bind for RPC calls.
|
||||
* ``webAddress``: The address the webserver should bind. Note that the port must be distinct from that of ``p2pAddress``
|
||||
and ``rpcAddress`` if they are on the same machine.
|
||||
* ``networkMapService``: Details of the node running the network map service. If it's this node that's running the service
|
||||
then this field must not be specified.
|
||||
|
||||
|
@ -807,16 +807,18 @@ like to deploy for testing. See further details below:
|
||||
name "Controller" // Artemis name of node to be deployed.
|
||||
nearestCity "London" // For use with the network visualiser.
|
||||
advertisedServices = ["corda.notary.validating"] // A list of services you wish the node to offer.
|
||||
artemisPort 10002
|
||||
webPort 10003 // Usually 1 higher than the Artemis port.
|
||||
p2pPort 10002
|
||||
rpcPort 10003 // Usually 1 higher than the messaging port.
|
||||
webPort 10004 // Usually 1 higher than the RPC port.
|
||||
cordapps = [] // Add package names of CordaApps.
|
||||
}
|
||||
node { // Create an additional node.
|
||||
name "NodeA"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
}
|
||||
...
|
||||
@ -875,9 +877,9 @@ You must now edit the configuration file for each node, including the
|
||||
controller. Open each node's config file (`[nodeName]/node.conf`), and make
|
||||
the following changes:
|
||||
|
||||
* Change the artemis address to the machine's ip address (e.g.
|
||||
`artemisAddress="10.18.0.166:10006"`)
|
||||
* Change the network map service details to the ip address of the machine where the
|
||||
* Change the Artemis messaging address to the machine's IP address (e.g.
|
||||
`p2pAddress="10.18.0.166:10006"`)
|
||||
* Change the network map service details to the IP address of the machine where the
|
||||
controller node is running and to its legal name (e.g. `networkMapService.address="10.18.0.166:10002"` and
|
||||
`networkMapService.legalName=controller`) (please note that the controller will not have the `networkMapService` config)
|
||||
|
||||
|
@ -92,7 +92,7 @@ class Cordform extends DefaultTask {
|
||||
Node networkMapNode = getNodeByName(networkMapNodeName)
|
||||
nodes.each {
|
||||
if(it != networkMapNode) {
|
||||
it.networkMapAddress(networkMapNode.getArtemisAddress(), networkMapNodeName)
|
||||
it.networkMapAddress(networkMapNode.getP2PAddress(), networkMapNodeName)
|
||||
}
|
||||
it.build(directory.toFile())
|
||||
}
|
||||
|
@ -80,13 +80,23 @@ class Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the artemis port for this node.
|
||||
* Set the Artemis P2P port for this node.
|
||||
*
|
||||
* @param artemisPort The artemis messaging queue port.
|
||||
* @param p2pPort The Artemis messaging queue port.
|
||||
*/
|
||||
void artemisPort(Integer artemisPort) {
|
||||
config = config.withValue("artemisAddress",
|
||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$artemisPort".toString()))
|
||||
void p2pPort(Integer p2pPort) {
|
||||
config = config.withValue("p2pAddress",
|
||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$p2pPort".toString()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Artemis RPC port for this node.
|
||||
*
|
||||
* @param rpcPort The Artemis RPC queue port.
|
||||
*/
|
||||
void rpcPort(Integer rpcPort) {
|
||||
config = config.withValue("rpcAddress",
|
||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$rpcPort".toString()))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,10 +150,10 @@ class Node {
|
||||
/**
|
||||
* Get the artemis address for this node.
|
||||
*
|
||||
* @return This node's artemis address.
|
||||
* @return This node's P2P address.
|
||||
*/
|
||||
String getArtemisAddress() {
|
||||
return config.getString("artemisAddress")
|
||||
String getP2PAddress() {
|
||||
return config.getString("p2pAddress")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,6 +14,9 @@ import org.junit.Test
|
||||
* Runs the security tests with the attacker pretending to be a node on the network.
|
||||
*/
|
||||
class MQSecurityAsNodeTest : MQSecurityTest() {
|
||||
override fun createAttacker(): SimpleMQClient {
|
||||
return clientTo(alice.configuration.p2pAddress)
|
||||
}
|
||||
|
||||
override fun startAttacker(attacker: SimpleMQClient) {
|
||||
attacker.start(PEER_USER, PEER_USER) // Login as a peer
|
||||
@ -26,7 +29,7 @@ class MQSecurityAsNodeTest : MQSecurityTest() {
|
||||
|
||||
@Test
|
||||
fun `only the node running the broker can login using the special node user`() {
|
||||
val attacker = clientTo(alice.configuration.artemisAddress)
|
||||
val attacker = clientTo(alice.configuration.p2pAddress)
|
||||
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
|
||||
attacker.start(NODE_USER, NODE_USER)
|
||||
}
|
||||
@ -34,7 +37,7 @@ class MQSecurityAsNodeTest : MQSecurityTest() {
|
||||
|
||||
@Test
|
||||
fun `login as the default cluster user`() {
|
||||
val attacker = clientTo(alice.configuration.artemisAddress)
|
||||
val attacker = clientTo(alice.configuration.p2pAddress)
|
||||
assertThatExceptionOfType(ActiveMQClusterSecurityException::class.java).isThrownBy {
|
||||
attacker.start(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword())
|
||||
}
|
||||
@ -42,9 +45,25 @@ class MQSecurityAsNodeTest : MQSecurityTest() {
|
||||
|
||||
@Test
|
||||
fun `login without a username and password`() {
|
||||
val attacker = clientTo(alice.configuration.artemisAddress)
|
||||
val attacker = clientTo(alice.configuration.p2pAddress)
|
||||
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
|
||||
attacker.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login to a non ssl port as a node user`() {
|
||||
val attacker = clientTo(alice.configuration.rpcAddress!!, sslConfiguration = null)
|
||||
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
|
||||
attacker.start(NODE_USER, NODE_USER, enableSSL = false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login to a non ssl port as a peer user`() {
|
||||
val attacker = clientTo(alice.configuration.rpcAddress!!, sslConfiguration = null)
|
||||
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
|
||||
attacker.start(PEER_USER, PEER_USER, enableSSL = false) // Login as a peer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,35 @@ package net.corda.services.messaging
|
||||
|
||||
import net.corda.node.services.User
|
||||
import net.corda.testing.messaging.SimpleMQClient
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Runs the security tests with the attacker being a valid RPC user of Alice.
|
||||
*/
|
||||
class MQSecurityAsRPCTest : MQSecurityTest() {
|
||||
override fun createAttacker(): SimpleMQClient {
|
||||
return clientTo(alice.configuration.rpcAddress!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `send message on logged in user's RPC address`() {
|
||||
val user1Queue = loginToRPCAndGetClientQueue()
|
||||
assertSendAttackFails(user1Queue)
|
||||
}
|
||||
|
||||
override val extraRPCUsers = listOf(User("evil", "pass", permissions = emptySet()))
|
||||
|
||||
override fun startAttacker(attacker: SimpleMQClient) {
|
||||
attacker.loginToRPC(extraRPCUsers[0])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login to a ssl port as a RPC user`() {
|
||||
val attacker = clientTo(alice.configuration.p2pAddress)
|
||||
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
|
||||
attacker.loginToRPC(extraRPCUsers[0], enableSSL = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import net.corda.core.utilities.unwrap
|
||||
import net.corda.node.internal.Node
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.config.SSLConfiguration
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
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.NETWORK_MAP_QUEUE
|
||||
@ -24,6 +23,7 @@ import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.PEE
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.RPC_QUEUE_REMOVALS_QUEUE
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.Companion.RPC_REQUESTS_QUEUE
|
||||
import net.corda.node.services.messaging.CordaRPCClientImpl
|
||||
import net.corda.testing.configureTestSSL
|
||||
import net.corda.testing.messaging.SimpleMQClient
|
||||
import net.corda.testing.node.NodeBasedTest
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
|
||||
@ -49,12 +49,14 @@ abstract class MQSecurityTest : NodeBasedTest() {
|
||||
@Before
|
||||
fun start() {
|
||||
alice = startNode("Alice", rpcUsers = extraRPCUsers + rpcUser).getOrThrow()
|
||||
attacker = clientTo(alice.configuration.artemisAddress)
|
||||
attacker = createAttacker()
|
||||
startAttacker(attacker)
|
||||
}
|
||||
|
||||
open val extraRPCUsers: List<User> get() = emptyList()
|
||||
|
||||
abstract fun createAttacker(): SimpleMQClient
|
||||
|
||||
abstract fun startAttacker(attacker: SimpleMQClient)
|
||||
|
||||
@After
|
||||
@ -112,12 +114,6 @@ abstract class MQSecurityTest : NodeBasedTest() {
|
||||
assertConsumeAttackFails(user1Queue)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `send message on logged in user's RPC address`() {
|
||||
val user1Queue = loginToRPCAndGetClientQueue()
|
||||
assertSendAttackFails(user1Queue)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `create queue for valid RPC user`() {
|
||||
val user1Queue = "$CLIENTS_PREFIX${rpcUser.username}.rpc.${random63BitValue()}"
|
||||
@ -152,26 +148,26 @@ abstract class MQSecurityTest : NodeBasedTest() {
|
||||
assertAllQueueCreationAttacksFail(randomQueue)
|
||||
}
|
||||
|
||||
fun clientTo(target: HostAndPort, config: SSLConfiguration = configureTestSSL()): SimpleMQClient {
|
||||
val client = SimpleMQClient(target, config)
|
||||
fun clientTo(target: HostAndPort, sslConfiguration: SSLConfiguration? = configureTestSSL()): SimpleMQClient {
|
||||
val client = SimpleMQClient(target, sslConfiguration)
|
||||
clients += client
|
||||
return client
|
||||
}
|
||||
|
||||
fun loginToRPC(target: HostAndPort, rpcUser: User): SimpleMQClient {
|
||||
val client = clientTo(target)
|
||||
fun loginToRPC(target: HostAndPort, rpcUser: User, sslConfiguration: SSLConfiguration? = null): SimpleMQClient {
|
||||
val client = clientTo(target, sslConfiguration)
|
||||
client.loginToRPC(rpcUser)
|
||||
return client
|
||||
}
|
||||
|
||||
fun SimpleMQClient.loginToRPC(rpcUser: User): CordaRPCOps {
|
||||
start(rpcUser.username, rpcUser.password)
|
||||
fun SimpleMQClient.loginToRPC(rpcUser: User, enableSSL: Boolean = false): CordaRPCOps {
|
||||
start(rpcUser.username, rpcUser.password, enableSSL)
|
||||
val clientImpl = CordaRPCClientImpl(session, ReentrantLock(), rpcUser.username)
|
||||
return clientImpl.proxyFor(CordaRPCOps::class.java, timeout = 1.seconds)
|
||||
}
|
||||
|
||||
fun loginToRPCAndGetClientQueue(): String {
|
||||
val rpcClient = loginToRPC(alice.configuration.artemisAddress, rpcUser)
|
||||
val rpcClient = loginToRPC(alice.configuration.rpcAddress!!, rpcUser)
|
||||
val clientQueueQuery = SimpleString("$CLIENTS_PREFIX${rpcUser.username}.rpc.*")
|
||||
return rpcClient.session.addressQuery(clientQueueQuery).queueNames.single().toString()
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class P2PSecurityTest : NodeBasedTest() {
|
||||
val incorrectNetworkMapName = random63BitValue().toString()
|
||||
val node = startNode("Bob", configOverrides = mapOf(
|
||||
"networkMapService" to mapOf(
|
||||
"address" to networkMapNode.configuration.artemisAddress.toString(),
|
||||
"address" to networkMapNode.configuration.p2pAddress.toString(),
|
||||
"legalName" to incorrectNetworkMapName
|
||||
)
|
||||
))
|
||||
@ -57,7 +57,7 @@ class P2PSecurityTest : NodeBasedTest() {
|
||||
val config = TestNodeConfiguration(
|
||||
baseDirectory = tempFolder.root.toPath() / legalName,
|
||||
myLegalName = legalName,
|
||||
networkMapService = NetworkMapInfo(networkMapNode.configuration.artemisAddress, networkMapNode.info.legalIdentity.name))
|
||||
networkMapService = NetworkMapInfo(networkMapNode.configuration.p2pAddress, networkMapNode.info.legalIdentity.name))
|
||||
config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name
|
||||
return SimpleNode(config).apply { start() }
|
||||
}
|
||||
@ -68,4 +68,4 @@ class P2PSecurityTest : NodeBasedTest() {
|
||||
val request = RegistrationRequest(registration.toWire(identity.private), net.myAddress)
|
||||
return net.sendRequest<NetworkMapService.RegistrationResponse>(NetworkMapService.REGISTER_TOPIC, request, networkMapNode.net.myAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
@file:JvmName("Corda")
|
||||
package net.corda.node
|
||||
|
||||
import com.typesafe.config.Config
|
||||
import com.jcabi.manifests.Manifests
|
||||
import com.typesafe.config.ConfigException
|
||||
import joptsimple.OptionException
|
||||
@ -80,7 +81,9 @@ fun main(args: Array<String>) {
|
||||
printBasicNodeInfo("Logs can be found in", System.getProperty("log-path"))
|
||||
|
||||
val conf = try {
|
||||
FullNodeConfiguration(cmdlineOptions.baseDirectory, cmdlineOptions.loadConfig())
|
||||
val conf = cmdlineOptions.loadConfig()
|
||||
checkConfigVersion(conf)
|
||||
FullNodeConfiguration(cmdlineOptions.baseDirectory, conf)
|
||||
} catch (e: ConfigException) {
|
||||
println("Unable to load the configuration file: ${e.rootCause.message}")
|
||||
exitProcess(2)
|
||||
@ -110,7 +113,7 @@ fun main(args: Array<String>) {
|
||||
log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}")
|
||||
log.info("Machine: ${InetAddress.getLocalHost().hostName}")
|
||||
log.info("Working Directory: ${cmdlineOptions.baseDirectory}")
|
||||
log.info("Starting as node on ${conf.artemisAddress}")
|
||||
log.info("Starting as node on ${conf.p2pAddress}")
|
||||
|
||||
try {
|
||||
cmdlineOptions.baseDirectory.createDirectories()
|
||||
@ -138,6 +141,16 @@ fun main(args: Array<String>) {
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
private fun checkConfigVersion(conf: Config) {
|
||||
// TODO: Remove this check in future milestone.
|
||||
if (conf.hasPath("artemisAddress")) {
|
||||
// artemisAddress has been renamed to p2pAddress in M10.
|
||||
println("artemisAddress has been renamed to p2pAddress in M10, please upgrade your configuration file and start Corda node again.")
|
||||
println("Corda will now exit...")
|
||||
exitProcess(1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkJavaVersion() {
|
||||
// Check we're not running a version of Java with a known bug: https://github.com/corda/corda/issues/83
|
||||
try {
|
||||
|
@ -105,7 +105,7 @@ data class NodeHandle(
|
||||
val configuration: FullNodeConfiguration,
|
||||
val process: Process
|
||||
) {
|
||||
fun rpcClientToNode(): CordaRPCClient = CordaRPCClient(configuration.artemisAddress, configuration)
|
||||
fun rpcClientToNode(): CordaRPCClient = CordaRPCClient(configuration.rpcAddress!!)
|
||||
}
|
||||
|
||||
sealed class PortAllocation {
|
||||
@ -342,16 +342,18 @@ open class DriverDSL(
|
||||
|
||||
override fun startNode(providedName: String?, advertisedServices: Set<ServiceInfo>,
|
||||
rpcUsers: List<User>, customOverrides: Map<String, Any?>): ListenableFuture<NodeHandle> {
|
||||
val messagingAddress = portAllocation.nextHostAndPort()
|
||||
val apiAddress = portAllocation.nextHostAndPort()
|
||||
val p2pAddress = portAllocation.nextHostAndPort()
|
||||
val rpcAddress = portAllocation.nextHostAndPort()
|
||||
val webAddress = portAllocation.nextHostAndPort()
|
||||
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
|
||||
val name = providedName ?: "${pickA(name)}-${messagingAddress.port}"
|
||||
val name = providedName ?: "${pickA(name)}-${p2pAddress.port}"
|
||||
|
||||
val baseDirectory = driverDirectory / name
|
||||
val configOverrides = mapOf(
|
||||
"myLegalName" to name,
|
||||
"artemisAddress" to messagingAddress.toString(),
|
||||
"webAddress" to apiAddress.toString(),
|
||||
"p2pAddress" to p2pAddress.toString(),
|
||||
"rpcAddress" to rpcAddress.toString(),
|
||||
"webAddress" to webAddress.toString(),
|
||||
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
|
||||
"networkMapService" to mapOf(
|
||||
"address" to networkMapAddress.toString(),
|
||||
@ -379,7 +381,8 @@ open class DriverDSL(
|
||||
val processFuture = startNode(executorService, configuration, quasarJarPath, debugPort)
|
||||
registerProcess(processFuture)
|
||||
return processFuture.flatMap { process ->
|
||||
establishRpc(messagingAddress, configuration).flatMap { rpc ->
|
||||
// We continue to use SSL enabled port for RPC when its for node user.
|
||||
establishRpc(p2pAddress, configuration).flatMap { rpc ->
|
||||
rpc.waitUntilRegisteredWithNetworkMap().map {
|
||||
NodeHandle(rpc.nodeIdentity(), rpc, configuration, process)
|
||||
}
|
||||
@ -465,7 +468,7 @@ open class DriverDSL(
|
||||
// TODO: remove the webAddress as NMS doesn't need to run a web server. This will cause all
|
||||
// node port numbers to be shifted, so all demos and docs need to be updated accordingly.
|
||||
"webAddress" to apiAddress,
|
||||
"artemisAddress" to networkMapAddress.toString(),
|
||||
"p2pAddress" to networkMapAddress.toString(),
|
||||
"useTestClock" to useTestClock
|
||||
)
|
||||
)
|
||||
@ -536,7 +539,7 @@ open class DriverDSL(
|
||||
val process = builder.start()
|
||||
// TODO There is a race condition here. Even though the messaging address is bound it may be the case that
|
||||
// the handlers for the advertised services are not yet registered. Needs rethinking.
|
||||
return addressMustBeBound(executorService, nodeConf.artemisAddress).map { process }
|
||||
return addressMustBeBound(executorService, nodeConf.p2pAddress).map { process }
|
||||
}
|
||||
|
||||
private fun startWebserver(
|
||||
@ -554,7 +557,7 @@ open class DriverDSL(
|
||||
emptyList()
|
||||
|
||||
val javaArgs = listOf(path) +
|
||||
listOf("-Dname=node-${nodeConf.artemisAddress}-webserver") + debugPortArg +
|
||||
listOf("-Dname=node-${nodeConf.p2pAddress}-webserver") + debugPortArg +
|
||||
listOf(
|
||||
"-cp", classpath, className,
|
||||
"--base-directory", nodeConf.baseDirectory.toString())
|
||||
|
@ -27,6 +27,7 @@ import net.corda.node.services.transactions.PersistentUniquenessProvider
|
||||
import net.corda.node.services.transactions.RaftUniquenessProvider
|
||||
import net.corda.node.services.transactions.RaftValidatingNotaryService
|
||||
import net.corda.node.utilities.AddressUtils
|
||||
import net.corda.node.services.transactions.*
|
||||
import net.corda.node.utilities.AffinityExecutor
|
||||
import org.slf4j.Logger
|
||||
import java.io.RandomAccessFile
|
||||
@ -141,9 +142,9 @@ class Node(override val configuration: FullNodeConfiguration,
|
||||
|
||||
private fun makeLocalMessageBroker(): HostAndPort {
|
||||
with(configuration) {
|
||||
val useHost = tryDetectIfNotPublicHost(artemisAddress.hostText)
|
||||
val useAddress = useHost?.let { HostAndPort.fromParts(it, artemisAddress.port) } ?: artemisAddress
|
||||
messageBroker = ArtemisMessagingServer(this, useAddress, services.networkMapCache, userService)
|
||||
val useHost = tryDetectIfNotPublicHost(p2pAddress.hostText)
|
||||
val useAddress = useHost?.let { HostAndPort.fromParts(it, p2pAddress.port) } ?: p2pAddress
|
||||
messageBroker = ArtemisMessagingServer(this, useAddress, rpcAddress, services.networkMapCache, userService)
|
||||
return useAddress
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import net.corda.core.div
|
||||
import net.corda.core.exists
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.time.Instant
|
||||
@ -49,6 +48,9 @@ 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
|
||||
@ -101,7 +103,7 @@ inline fun <reified T : Any> Config.getListOrElse(path: String, default: Config.
|
||||
*/
|
||||
fun NodeConfiguration.configureWithDevSSLCertificate() = configureDevKeyAndTrustStores(myLegalName)
|
||||
|
||||
private fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: String) {
|
||||
fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: String) {
|
||||
certificatesDirectory.createDirectories()
|
||||
if (!trustStoreFile.exists()) {
|
||||
javaClass.classLoader.getResourceAsStream("net/corda/node/internal/certificates/cordatruststore.jks").copyTo(trustStoreFile)
|
||||
@ -113,15 +115,3 @@ private fun SSLConfiguration.configureDevKeyAndTrustStores(myLegalName: String)
|
||||
X509Utilities.createKeystoreForSSL(keyStoreFile, keyStorePassword, keyStorePassword, caKeyStore, "cordacadevkeypass", myLegalName)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Move this to CoreTestUtils.kt once we can pry this from the explorer
|
||||
@JvmOverloads
|
||||
fun configureTestSSL(legalName: String = "Mega Corp."): SSLConfiguration = object : SSLConfiguration {
|
||||
override val certificatesDirectory = Files.createTempDirectory("certs")
|
||||
override val keyStorePassword: String get() = "cordacadevpass"
|
||||
override val trustStorePassword: String get() = "trustpass"
|
||||
|
||||
init {
|
||||
configureDevKeyAndTrustStores(legalName)
|
||||
}
|
||||
}
|
||||
|
@ -65,15 +65,16 @@ class FullNodeConfiguration(override val baseDirectory: Path, val config: Config
|
||||
User(username, password, permissions)
|
||||
}
|
||||
val useHTTPS: Boolean by config
|
||||
val artemisAddress: HostAndPort by config
|
||||
val p2pAddress: HostAndPort by config
|
||||
val rpcAddress: HostAndPort? by config
|
||||
val webAddress: HostAndPort by config
|
||||
// TODO This field is slightly redundant as artemisAddress is sufficient to hold the address of the node's MQ broker.
|
||||
// TODO This field is slightly redundant as p2pAddress is sufficient to hold the address of the node's MQ broker.
|
||||
// Instead this should be a Boolean indicating whether that broker is an internal one started by the node or an external one
|
||||
val messagingServerAddress: HostAndPort? by config.getOrElse { null }
|
||||
val messagingServerAddress: HostAndPort? by config
|
||||
val extraAdvertisedServiceIds: List<String> = config.getListOrElse<String>("extraAdvertisedServiceIds") { emptyList() }
|
||||
val useTestClock: Boolean by config.getOrElse { false }
|
||||
val notaryNodeId: Int? by config.getOrElse { null }
|
||||
val notaryNodeAddress: HostAndPort? by config.getOrElse { null }
|
||||
val notaryNodeId: Int? by config
|
||||
val notaryNodeAddress: HostAndPort? by config
|
||||
val notaryClusterAddresses: List<HostAndPort> = config
|
||||
.getListOrElse<String>("notaryClusterAddresses") { emptyList() }
|
||||
.map { HostAndPort.fromString(it) }
|
||||
|
@ -22,7 +22,7 @@ import java.security.KeyStore
|
||||
/**
|
||||
* The base class for Artemis services that defines shared data structures and SSL transport configuration.
|
||||
*/
|
||||
abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
|
||||
abstract class ArtemisMessagingComponent : SingletonSerializeAsToken() {
|
||||
companion object {
|
||||
init {
|
||||
System.setProperty("org.jboss.logging.provider", "slf4j")
|
||||
@ -88,6 +88,7 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
|
||||
fun asPeer(peerIdentity: CompositeKey, hostAndPort: HostAndPort): NodeAddress {
|
||||
return NodeAddress("$PEERS_PREFIX${peerIdentity.toBase58String()}", hostAndPort)
|
||||
}
|
||||
|
||||
fun asService(serviceIdentity: CompositeKey, hostAndPort: HostAndPort): NodeAddress {
|
||||
return NodeAddress("$SERVICES_PREFIX${serviceIdentity.toBase58String()}", hostAndPort)
|
||||
}
|
||||
@ -137,7 +138,10 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
|
||||
}
|
||||
}
|
||||
|
||||
protected fun tcpTransport(direction: ConnectionDirection, host: String, port: Int): TransportConfiguration {
|
||||
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
|
||||
@ -151,7 +155,7 @@ abstract class ArtemisMessagingComponent() : SingletonSerializeAsToken() {
|
||||
TransportConstants.PROTOCOLS_PROP_NAME to "CORE,AMQP"
|
||||
)
|
||||
|
||||
if (config != null) {
|
||||
if (config != null && enableSSL) {
|
||||
config.keyStoreFile.expectedOnDefaultFileSystem()
|
||||
config.trustStoreFile.expectedOnDefaultFileSystem()
|
||||
val tlsOptions = mapOf<String, Any?>(
|
||||
|
@ -81,7 +81,8 @@ import javax.security.cert.X509Certificate
|
||||
*/
|
||||
@ThreadSafe
|
||||
class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
val myHostPort: HostAndPort,
|
||||
val p2pHostPort: HostAndPort,
|
||||
val rpcHostPort: HostAndPort?,
|
||||
val networkMapCache: NetworkMapCache,
|
||||
val userService: RPCUserService) : ArtemisMessagingComponent() {
|
||||
companion object {
|
||||
@ -139,7 +140,10 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
registerPostQueueDeletionCallback { address, qName -> log.debug { "Queue deleted: $qName for $address" } }
|
||||
}
|
||||
activeMQServer.start()
|
||||
printBasicNodeInfo("Node ${this.config.myLegalName} listening on address", myHostPort.toString())
|
||||
printBasicNodeInfo("Node ${this.config.myLegalName} listening on address", p2pHostPort.toString())
|
||||
if (rpcHostPort != null) {
|
||||
printBasicNodeInfo("Node ${this.config.myLegalName} RPC service listening on address", rpcHostPort.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createArtemisConfig(): Configuration = ConfigurationImpl().apply {
|
||||
@ -147,7 +151,11 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
bindingsDirectory = (artemisDir / "bindings").toString()
|
||||
journalDirectory = (artemisDir / "journal").toString()
|
||||
largeMessagesDirectory = (artemisDir / "large-messages").toString()
|
||||
acceptorConfigurations = setOf(tcpTransport(Inbound, "0.0.0.0", myHostPort.port))
|
||||
val acceptors = mutableSetOf(tcpTransport(Inbound, "0.0.0.0", p2pHostPort.port))
|
||||
if (rpcHostPort != null) {
|
||||
acceptors.add(tcpTransport(Inbound, "0.0.0.0", rpcHostPort.port, enableSSL = false))
|
||||
}
|
||||
acceptorConfigurations = acceptors
|
||||
// Enable built in message deduplication. Note we still have to do our own as the delayed commits
|
||||
// and our own definition of commit mean that the built in deduplication cannot remove all duplicates.
|
||||
idCacheSize = 2000 // Artemis Default duplicate cache size i.e. a guess
|
||||
@ -160,15 +168,15 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
// by having its password be an unknown securely random 128-bit value.
|
||||
clusterPassword = BigInteger(128, newSecureRandom()).toString(16)
|
||||
queueConfigurations = listOf(
|
||||
queueConfig(NETWORK_MAP_QUEUE, durable = true),
|
||||
queueConfig(P2P_QUEUE, durable = true),
|
||||
// Create an RPC queue: this will service locally connected clients only (not via a bridge) and those
|
||||
// clients must have authenticated. We could use a single consumer for everything and perhaps we should,
|
||||
// but these queues are not worth persisting.
|
||||
queueConfig(RPC_REQUESTS_QUEUE, durable = false),
|
||||
// The custom name for the queue is intentional - we may wish other things to subscribe to the
|
||||
// NOTIFICATIONS_ADDRESS with different filters in future
|
||||
queueConfig(RPC_QUEUE_REMOVALS_QUEUE, address = NOTIFICATIONS_ADDRESS, filter = "_AMQ_NotifType = 1", durable = false)
|
||||
queueConfig(NETWORK_MAP_QUEUE, durable = true),
|
||||
queueConfig(P2P_QUEUE, durable = true),
|
||||
// Create an RPC queue: this will service locally connected clients only (not via a bridge) and those
|
||||
// clients must have authenticated. We could use a single consumer for everything and perhaps we should,
|
||||
// but these queues are not worth persisting.
|
||||
queueConfig(RPC_REQUESTS_QUEUE, durable = false),
|
||||
// The custom name for the queue is intentional - we may wish other things to subscribe to the
|
||||
// NOTIFICATIONS_ADDRESS with different filters in future
|
||||
queueConfig(RPC_QUEUE_REMOVALS_QUEUE, address = NOTIFICATIONS_ADDRESS, filter = "_AMQ_NotifType = 1", durable = false)
|
||||
)
|
||||
configureAddressSecurity()
|
||||
}
|
||||
@ -290,8 +298,8 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
|
||||
fun deployBridges(node: NodeInfo) {
|
||||
gatherAddresses(node)
|
||||
.filter { queueExists(it.queueName) && !bridgeExists(it.bridgeName) }
|
||||
.forEach { deployBridge(it, node.legalIdentity.name) }
|
||||
.filter { queueExists(it.queueName) && !bridgeExists(it.bridgeName) }
|
||||
.forEach { deployBridge(it, node.legalIdentity.name) }
|
||||
}
|
||||
|
||||
fun destroyBridges(node: NodeInfo) {
|
||||
@ -397,8 +405,7 @@ private class VerifyingNettyConnector(configuration: MutableMap<String, Any>?,
|
||||
threadPool: Executor?,
|
||||
scheduledThreadPool: ScheduledExecutorService?,
|
||||
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 expectedCommonName = configuration?.get(ArtemisMessagingComponent.VERIFY_PEER_COMMON_NAME) as? String
|
||||
|
||||
@ -480,15 +487,15 @@ class NodeLoginModule : LoginModule {
|
||||
|
||||
val username = nameCallback.name ?: throw FailedLoginException("Username not provided")
|
||||
val password = String(passwordCallback.password ?: throw FailedLoginException("Password not provided"))
|
||||
val certificates = certificateCallback.certificates
|
||||
|
||||
log.info("Processing login for $username")
|
||||
|
||||
val validatedUser = if (username == PEER_USER || username == NODE_USER) {
|
||||
val certificates = certificateCallback.certificates ?: throw FailedLoginException("No TLS?")
|
||||
authenticateNode(certificates, username)
|
||||
} else {
|
||||
// Otherwise assume they're an RPC user
|
||||
authenticateRpcUser(password, username)
|
||||
val validatedUser = when (determineUserRole(certificates, username)) {
|
||||
PEER_ROLE -> authenticatePeer(certificates)
|
||||
NODE_ROLE -> authenticateNode(certificates)
|
||||
RPC_ROLE -> authenticateRpcUser(password, username)
|
||||
else -> throw FailedLoginException("Peer does not belong on our network")
|
||||
}
|
||||
principals += UserPrincipal(validatedUser)
|
||||
|
||||
@ -496,24 +503,24 @@ class NodeLoginModule : LoginModule {
|
||||
return loginSucceeded
|
||||
}
|
||||
|
||||
private fun authenticateNode(certificates: Array<X509Certificate>, username: String): String {
|
||||
private fun authenticateNode(certificates: Array<X509Certificate>): String {
|
||||
val peerCertificate = certificates.first()
|
||||
val role = if (username == NODE_USER) {
|
||||
if (peerCertificate.publicKey != ourPublicKey) {
|
||||
throw FailedLoginException("Only the node can login as $NODE_USER")
|
||||
}
|
||||
NODE_ROLE
|
||||
} else {
|
||||
val theirRootCAPublicKey = certificates.last().publicKey
|
||||
if (theirRootCAPublicKey != ourRootCAPublicKey) {
|
||||
throw FailedLoginException("Peer does not belong on our network. Their root CA: $theirRootCAPublicKey")
|
||||
}
|
||||
PEER_ROLE // This enables the peer to send to our P2P address
|
||||
if (peerCertificate.publicKey != ourPublicKey) {
|
||||
throw FailedLoginException("Only the node can login as $NODE_USER")
|
||||
}
|
||||
principals += RolePrincipal(role)
|
||||
principals += RolePrincipal(NODE_ROLE)
|
||||
return peerCertificate.subjectDN.name
|
||||
}
|
||||
|
||||
private fun authenticatePeer(certificates: Array<X509Certificate>): String {
|
||||
val theirRootCAPublicKey = certificates.last().publicKey
|
||||
if (theirRootCAPublicKey != ourRootCAPublicKey) {
|
||||
throw FailedLoginException("Peer does not belong on our network. Their root CA: $theirRootCAPublicKey")
|
||||
}
|
||||
principals += RolePrincipal(PEER_ROLE)
|
||||
return certificates.first().subjectDN.name
|
||||
}
|
||||
|
||||
private fun authenticateRpcUser(password: String, username: String): String {
|
||||
val rpcUser = userService.getUser(username) ?: throw FailedLoginException("User does not exist")
|
||||
if (password != rpcUser.password) {
|
||||
@ -526,6 +533,18 @@ class NodeLoginModule : LoginModule {
|
||||
return username
|
||||
}
|
||||
|
||||
private fun determineUserRole(certificates: Array<X509Certificate>?, username: String): String? {
|
||||
return if (username == PEER_USER || username == NODE_USER) {
|
||||
certificates ?: throw FailedLoginException("No TLS?")
|
||||
if (username == PEER_USER) PEER_ROLE else NODE_ROLE
|
||||
} else if (certificates == null) {
|
||||
// Assume they're an RPC user if its from a non-ssl connection
|
||||
RPC_ROLE
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun commit(): Boolean {
|
||||
val result = loginSucceeded
|
||||
if (result) {
|
||||
|
@ -24,10 +24,10 @@ import javax.annotation.concurrent.ThreadSafe
|
||||
* useful tasks. See the documentation for [proxy] or review the docsite to learn more about how this API works.
|
||||
*
|
||||
* @param host The hostname and messaging port of the node.
|
||||
* @param config If specified, the SSL configuration to use. If not specified, SSL will be disabled and the node will not be authenticated, nor will RPC traffic be encrypted.
|
||||
* @param config If specified, the SSL configuration to use. If not specified, SSL will be disabled and the node will only be authenticated on non-SSL RPC port, the RPC traffic with not be encrypted when SSL is disabled.
|
||||
*/
|
||||
@ThreadSafe
|
||||
class CordaRPCClient(val host: HostAndPort, override val config: SSLConfiguration?, val serviceConfigurationOverride: (ServerLocator.() -> Unit)? = null) : Closeable, ArtemisMessagingComponent() {
|
||||
class CordaRPCClient(val host: HostAndPort, override val config: SSLConfiguration? = null, val serviceConfigurationOverride: (ServerLocator.() -> Unit)? = null) : Closeable, ArtemisMessagingComponent() {
|
||||
private companion object {
|
||||
val log = loggerFor<CordaRPCClient>()
|
||||
}
|
||||
@ -52,7 +52,7 @@ class CordaRPCClient(val host: HostAndPort, override val config: SSLConfiguratio
|
||||
check(!running)
|
||||
log.logElapsedTime("Startup") {
|
||||
checkStorePasswords()
|
||||
val serverLocator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport(Outbound(), host.hostText, host.port)).apply {
|
||||
val serverLocator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport(Outbound(), host.hostText, host.port, enableSSL = config != null)).apply {
|
||||
// TODO: Put these in config file or make it user configurable?
|
||||
threadPoolMaxSize = 1
|
||||
confirmationWindowSize = 100000 // a guess
|
||||
|
@ -48,6 +48,7 @@ class ArtemisMessagingTests {
|
||||
@Rule @JvmField val temporaryFolder = TemporaryFolder()
|
||||
|
||||
val hostAndPort = freeLocalHostAndPort()
|
||||
val rpcHostAndPort = freeLocalHostAndPort()
|
||||
val topic = "platform.self"
|
||||
val identity = generateKeyPair()
|
||||
|
||||
@ -232,8 +233,8 @@ class ArtemisMessagingTests {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMessagingServer(local: HostAndPort = hostAndPort): ArtemisMessagingServer {
|
||||
return ArtemisMessagingServer(config, local, networkMapCache, userService).apply {
|
||||
private fun createMessagingServer(local: HostAndPort = hostAndPort, rpc: HostAndPort = rpcHostAndPort): ArtemisMessagingServer {
|
||||
return ArtemisMessagingServer(config, local, rpc, networkMapCache, userService).apply {
|
||||
config.configureWithDevSSLCertificate()
|
||||
messagingServer = this
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ class NodeWebServer(val config: FullNodeConfiguration) {
|
||||
try {
|
||||
return connectLocalRpcAsNodeUser()
|
||||
} catch (e: ActiveMQNotConnectedException) {
|
||||
log.debug("Could not connect to ${config.artemisAddress} due to exception: ", e)
|
||||
log.debug("Could not connect to ${config.p2pAddress} due to exception: ", e)
|
||||
Thread.sleep(retryDelay)
|
||||
// This error will happen if the server has yet to create the keystore
|
||||
// Keep the fully qualified package name due to collisions with the Kotlin stdlib
|
||||
@ -166,8 +166,8 @@ class NodeWebServer(val config: FullNodeConfiguration) {
|
||||
}
|
||||
|
||||
private fun connectLocalRpcAsNodeUser(): CordaRPCOps {
|
||||
log.info("Connecting to node at ${config.artemisAddress} as node user")
|
||||
val client = CordaRPCClient(config.artemisAddress, config)
|
||||
log.info("Connecting to node at ${config.p2pAddress} as node user")
|
||||
val client = CordaRPCClient(config.p2pAddress, config)
|
||||
client.start(ArtemisMessagingComponent.NODE_USER, ArtemisMessagingComponent.NODE_USER)
|
||||
return client.proxy()
|
||||
}
|
||||
@ -176,4 +176,4 @@ class NodeWebServer(val config: FullNodeConfiguration) {
|
||||
val pluginRegistries: List<CordaPluginRegistry> by lazy {
|
||||
ServiceLoader.load(CordaPluginRegistry::class.java).toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
gradlePluginsVersion=0.8.3
|
||||
gradlePluginsVersion=0.10.0
|
||||
|
@ -69,8 +69,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Controller"
|
||||
nearestCity "London"
|
||||
advertisedServices ["corda.notary.validating"]
|
||||
artemisPort 10002
|
||||
webPort 10003
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
webPort 10004
|
||||
cordapps = []
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
@ -78,8 +79,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank A"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
@ -87,8 +89,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank B"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 10006
|
||||
webPort 10007
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps = []
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ fun main(args: Array<String>) {
|
||||
val parser = OptionParser()
|
||||
|
||||
val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).required()
|
||||
val certsPath = parser.accepts("certificates").withRequiredArg()
|
||||
val options = try {
|
||||
parser.parse(*args)
|
||||
} catch (e: Exception) {
|
||||
@ -40,16 +39,16 @@ fun main(args: Array<String>) {
|
||||
val role = options.valueOf(roleArg)!!
|
||||
when (role) {
|
||||
Role.SENDER -> {
|
||||
val host = HostAndPort.fromString("localhost:10004")
|
||||
val host = HostAndPort.fromString("localhost:10006")
|
||||
println("Connecting to sender node ($host)")
|
||||
CordaRPCClient(host, sslConfigFor("BankA", options.valueOf(certsPath))).use("demo", "demo") {
|
||||
CordaRPCClient(host).use("demo", "demo") {
|
||||
sender(this)
|
||||
}
|
||||
}
|
||||
Role.RECIPIENT -> {
|
||||
val host = HostAndPort.fromString("localhost:10006")
|
||||
val host = HostAndPort.fromString("localhost:10009")
|
||||
println("Connecting to the recipient node ($host)")
|
||||
CordaRPCClient(host, sslConfigFor("BankB", options.valueOf(certsPath))).use("demo", "demo") {
|
||||
CordaRPCClient(host).use("demo", "demo") {
|
||||
recipient(this)
|
||||
}
|
||||
}
|
||||
@ -111,7 +110,6 @@ private fun printHelp(parser: OptionParser) {
|
||||
parser.printHelpOn(System.out)
|
||||
}
|
||||
|
||||
|
||||
// TODO: Take this out once we have a dedicated RPC port and allow SSL on it to be optional.
|
||||
private fun sslConfigFor(nodename: String, certsPath: String?): SSLConfiguration {
|
||||
return object : SSLConfiguration {
|
||||
|
@ -66,16 +66,18 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Notary"
|
||||
nearestCity "London"
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
artemisPort 10002
|
||||
webPort 10003
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
webPort 10004
|
||||
cordapps = []
|
||||
}
|
||||
node {
|
||||
name "BankOfCorda"
|
||||
nearestCity "London"
|
||||
advertisedServices = ["corda.issuer.USD"]
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
rpcUsers = [
|
||||
['user' : "bankUser",
|
||||
@ -88,8 +90,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "BigCorporation"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 10006
|
||||
webPort 10007
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps = []
|
||||
rpcUsers = [
|
||||
['user' : "bigCorpUser",
|
||||
|
@ -66,13 +66,13 @@ private class BankOfCordaDriver {
|
||||
when (role) {
|
||||
Role.ISSUE_CASH_RPC -> {
|
||||
println("Requesting Cash via RPC ...")
|
||||
val result = BankOfCordaClientApi(HostAndPort.fromString("localhost:10004")).requestRPCIssue(requestParams)
|
||||
val result = BankOfCordaClientApi(HostAndPort.fromString("localhost:10006")).requestRPCIssue(requestParams)
|
||||
if (result is SignedTransaction)
|
||||
println("Success!! You transaction receipt is ${result.tx.id}")
|
||||
}
|
||||
Role.ISSUE_CASH_WEB -> {
|
||||
println("Requesting Cash via Web ...")
|
||||
val result = BankOfCordaClientApi(HostAndPort.fromString("localhost:10005")).requestWebIssue(requestParams)
|
||||
val result = BankOfCordaClientApi(HostAndPort.fromString("localhost:10007")).requestWebIssue(requestParams)
|
||||
if (result)
|
||||
println("Successfully processed Cash Issue request")
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.CordaRPCClient
|
||||
import net.corda.testing.http.HttpApi
|
||||
|
||||
@ -26,11 +25,12 @@ class BankOfCordaClientApi(val hostAndPort: HostAndPort) {
|
||||
val api = HttpApi.fromHostAndPort(hostAndPort, apiRoot)
|
||||
return api.postJson("issue-asset-request", params)
|
||||
}
|
||||
|
||||
/**
|
||||
* RPC API
|
||||
*/
|
||||
fun requestRPCIssue(params: IssueRequestParams): SignedTransaction {
|
||||
val client = CordaRPCClient(hostAndPort, configureTestSSL())
|
||||
val client = CordaRPCClient(hostAndPort)
|
||||
// TODO: privileged security controls required
|
||||
client.start("bankUser", "test")
|
||||
val proxy = client.proxy()
|
||||
|
@ -70,8 +70,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Notary"
|
||||
nearestCity "London"
|
||||
advertisedServices = ["corda.notary.validating", "corda.interest_rates"]
|
||||
artemisPort 10002
|
||||
webPort 10003
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
webPort 10004
|
||||
cordapps = []
|
||||
useTestClock true
|
||||
}
|
||||
@ -79,8 +80,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank A"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
useTestClock true
|
||||
}
|
||||
@ -88,8 +90,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank B"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 10006
|
||||
webPort 10007
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps = []
|
||||
useTestClock true
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class IRSDemoTest : IntegrationTestCategory {
|
||||
}
|
||||
|
||||
fun getFixingDateObservable(config: FullNodeConfiguration): BlockingObservable<LocalDate?> {
|
||||
val client = CordaRPCClient(config.artemisAddress, config)
|
||||
val client = CordaRPCClient(config.rpcAddress!!)
|
||||
client.start("user", "password")
|
||||
val proxy = client.proxy()
|
||||
val vaultUpdates = proxy.vaultAndUpdates().second
|
||||
|
@ -30,9 +30,9 @@ fun main(args: Array<String>) {
|
||||
val role = options.valueOf(roleArg)!!
|
||||
val value = options.valueOf(valueArg)
|
||||
when (role) {
|
||||
Role.UploadRates -> IRSDemoClientApi(HostAndPort.fromString("localhost:10003")).runUploadRates()
|
||||
Role.Trade -> IRSDemoClientApi(HostAndPort.fromString("localhost:10005")).runTrade(value)
|
||||
Role.Date -> IRSDemoClientApi(HostAndPort.fromString("localhost:10007")).runDateChange(value)
|
||||
Role.UploadRates -> IRSDemoClientApi(HostAndPort.fromString("localhost:10004")).runUploadRates()
|
||||
Role.Trade -> IRSDemoClientApi(HostAndPort.fromString("localhost:10007")).runTrade(value)
|
||||
Role.Date -> IRSDemoClientApi(HostAndPort.fromString("localhost:10010")).runDateChange(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build', 'generat
|
||||
name "Party"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10002
|
||||
webPort 10003
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
webPort 10004
|
||||
cordapps = []
|
||||
rpcUsers = [['user': "demo", 'password': "demo", 'permissions': [
|
||||
'StartFlow.net.corda.notarydemo.flows.DummyIssueAndMove',
|
||||
@ -101,16 +102,18 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build', 'generat
|
||||
name "Counterparty"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
}
|
||||
node {
|
||||
name "Notary 1"
|
||||
nearestCity "London"
|
||||
advertisedServices = [advertisedNotary]
|
||||
artemisPort 10007
|
||||
webPort 10008
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps = []
|
||||
notaryNodePort 11002
|
||||
}
|
||||
@ -118,8 +121,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build', 'generat
|
||||
name "Notary 2"
|
||||
nearestCity "London"
|
||||
advertisedServices = [advertisedNotary]
|
||||
artemisPort 10010
|
||||
webPort 10011
|
||||
p2pPort 10011
|
||||
rpcPort 10012
|
||||
webPort 10013
|
||||
cordapps = []
|
||||
notaryNodePort 11004
|
||||
notaryClusterAddresses = ["localhost:11002"]
|
||||
@ -128,8 +132,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build', 'generat
|
||||
name "Notary 3"
|
||||
nearestCity "London"
|
||||
advertisedServices = [advertisedNotary]
|
||||
artemisPort 10013
|
||||
webPort 10014
|
||||
p2pPort 10014
|
||||
rpcPort 10015
|
||||
webPort 10016
|
||||
cordapps = []
|
||||
notaryNodePort 11006
|
||||
notaryClusterAddresses = ["localhost:11002"]
|
||||
|
@ -18,10 +18,9 @@ import java.nio.file.Paths
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val certPath = getCertPath(args)
|
||||
val host = HostAndPort.fromString("localhost:10002")
|
||||
val host = HostAndPort.fromString("localhost:10003")
|
||||
println("Connecting to the recipient node ($host)")
|
||||
CordaRPCClient(host, sslConfigFor("Party", certPath)).use("demo", "demo") {
|
||||
CordaRPCClient(host).use("demo", "demo") {
|
||||
val api = NotaryDemoClientApi(this)
|
||||
api.startNotarisation()
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Controller"
|
||||
nearestCity "London"
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
artemisPort 10002
|
||||
p2pPort 10002
|
||||
webPort 10003
|
||||
cordapps = []
|
||||
}
|
||||
@ -93,7 +93,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank A"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
p2pPort 10004
|
||||
webPort 10005
|
||||
cordapps = []
|
||||
}
|
||||
@ -101,7 +101,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank B"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 10006
|
||||
p2pPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
}
|
||||
@ -109,7 +109,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank C"
|
||||
nearestCity "tokyo"
|
||||
advertisedServices = []
|
||||
artemisPort 10008
|
||||
p2pPort 10008
|
||||
webPort 10009
|
||||
cordapps = []
|
||||
}
|
||||
|
@ -81,16 +81,17 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Notary"
|
||||
nearestCity "London"
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
artemisPort 10002
|
||||
webPort 10003
|
||||
p2pPort 10002
|
||||
webPort 10004
|
||||
cordapps = []
|
||||
}
|
||||
node {
|
||||
name "Bank A"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10004
|
||||
webPort 10005
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
@ -98,8 +99,9 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "Bank B"
|
||||
nearestCity "New York"
|
||||
advertisedServices = []
|
||||
artemisPort 10006
|
||||
webPort 10007
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps = []
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
@ -107,8 +109,8 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
|
||||
name "BankOfCorda"
|
||||
nearestCity "London"
|
||||
advertisedServices = []
|
||||
artemisPort 10008
|
||||
webPort 10009
|
||||
p2pPort 10011
|
||||
webPort 10012
|
||||
cordapps = []
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class TraderDemoTest : NodeBasedTest() {
|
||||
).getOrThrow()
|
||||
|
||||
val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map {
|
||||
val client = CordaRPCClient(it.configuration.artemisAddress, it.configuration)
|
||||
val client = CordaRPCClient(it.configuration.rpcAddress!!)
|
||||
client.start(demoUser[0].username, demoUser[0].password).proxy()
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@ private class TraderDemo {
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val parser = OptionParser()
|
||||
val certsPath = parser.accepts("certificates").withRequiredArg()
|
||||
|
||||
val roleArg = parser.accepts("role").withRequiredArg().ofType(Role::class.java).required()
|
||||
val options = try {
|
||||
@ -46,13 +45,13 @@ private class TraderDemo {
|
||||
// will contact the buyer and actually make something happen.
|
||||
val role = options.valueOf(roleArg)!!
|
||||
if (role == Role.BUYER) {
|
||||
val host = HostAndPort.fromString("localhost:10004")
|
||||
CordaRPCClient(host, sslConfigFor("BankA", options.valueOf(certsPath))).use("demo", "demo") {
|
||||
val host = HostAndPort.fromString("localhost:10006")
|
||||
CordaRPCClient(host).use("demo", "demo") {
|
||||
TraderDemoClientApi(this).runBuyer()
|
||||
}
|
||||
} else {
|
||||
val host = HostAndPort.fromString("localhost:10006")
|
||||
CordaRPCClient(host, sslConfigFor("BankB", options.valueOf(certsPath))).use("demo", "demo") {
|
||||
val host = HostAndPort.fromString("localhost:10009")
|
||||
CordaRPCClient(host).use("demo", "demo") {
|
||||
TraderDemoClientApi(this).runSeller(1000.DOLLARS, "Bank A")
|
||||
}
|
||||
}
|
||||
@ -66,13 +65,4 @@ private class TraderDemo {
|
||||
""".trimIndent())
|
||||
parser.printHelpOn(System.out)
|
||||
}
|
||||
|
||||
// TODO: Take this out once we have a dedicated RPC port and allow SSL on it to be optional.
|
||||
private fun sslConfigFor(nodename: String, certsPath: String?): SSLConfiguration {
|
||||
return object : SSLConfiguration {
|
||||
override val keyStorePassword: String = "cordacadevpass"
|
||||
override val trustStorePassword: String = "trustpass"
|
||||
override val certificatesDirectory: Path = if (certsPath != null) Paths.get(certsPath) else Paths.get("build") / "nodes" / nodename / "certificates"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ package net.corda.testing
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.typesafe.config.Config
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.flows.FlowLogic
|
||||
@ -19,6 +20,8 @@ import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||
import net.corda.node.internal.AbstractNode
|
||||
import net.corda.node.internal.NetworkMapInfo
|
||||
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.statemachine.FlowStateMachineImpl
|
||||
import net.corda.node.utilities.AddOrRemove.ADD
|
||||
import net.corda.testing.node.MockIdentityService
|
||||
@ -26,6 +29,7 @@ import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.makeTestDataSourceProperties
|
||||
import java.net.ServerSocket
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
@ -163,3 +167,16 @@ data class TestNodeConfiguration(
|
||||
override val exportJMXto: String = "",
|
||||
override val devMode: Boolean = true,
|
||||
override val certificateSigningService: URL = URL("http://localhost")) : NodeConfiguration
|
||||
|
||||
fun Config.getHostAndPort(name: String) = HostAndPort.fromString(getString(name))
|
||||
|
||||
@JvmOverloads
|
||||
fun configureTestSSL(legalName: String = "Mega Corp."): SSLConfiguration = object : SSLConfiguration {
|
||||
override val certificatesDirectory = Files.createTempDirectory("certs")
|
||||
override val keyStorePassword: String get() = "cordacadevpass"
|
||||
override val trustStorePassword: String get() = "trustpass"
|
||||
|
||||
init {
|
||||
configureDevKeyAndTrustStores(legalName)
|
||||
}
|
||||
}
|
||||
|
@ -2,22 +2,22 @@ package net.corda.testing.messaging
|
||||
|
||||
import com.google.common.net.HostAndPort
|
||||
import net.corda.node.services.config.SSLConfiguration
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent.ConnectionDirection.Outbound
|
||||
import net.corda.testing.configureTestSSL
|
||||
import org.apache.activemq.artemis.api.core.client.*
|
||||
|
||||
/**
|
||||
* As the name suggests this is a simple client for connecting to MQ brokers.
|
||||
*/
|
||||
class SimpleMQClient(val target: HostAndPort,
|
||||
override val config: SSLConfiguration = configureTestSSL("SimpleMQClient")) : ArtemisMessagingComponent() {
|
||||
override val config: SSLConfiguration? = configureTestSSL("SimpleMQClient")) : ArtemisMessagingComponent() {
|
||||
lateinit var sessionFactory: ClientSessionFactory
|
||||
lateinit var session: ClientSession
|
||||
lateinit var producer: ClientProducer
|
||||
|
||||
fun start(username: String? = null, password: String? = null) {
|
||||
val tcpTransport = tcpTransport(Outbound(), target.hostText, target.port)
|
||||
fun start(username: String? = null, password: String? = null, enableSSL: Boolean = true) {
|
||||
val tcpTransport = tcpTransport(Outbound(), target.hostText, target.port, enableSSL)
|
||||
val locator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport).apply {
|
||||
isBlockOnNonDurableSend = true
|
||||
threadPoolMaxSize = 1
|
||||
|
@ -73,7 +73,7 @@ abstract class NodeBasedTest {
|
||||
rpcUsers,
|
||||
mapOf(
|
||||
"networkMapService" to mapOf(
|
||||
"address" to networkMapNode.configuration.artemisAddress.toString(),
|
||||
"address" to networkMapNode.configuration.p2pAddress.toString(),
|
||||
"legalName" to networkMapNode.info.legalIdentity.name
|
||||
)
|
||||
) + configOverrides
|
||||
@ -121,7 +121,8 @@ abstract class NodeBasedTest {
|
||||
allowMissingConfig = true,
|
||||
configOverrides = mapOf(
|
||||
"myLegalName" to legalName,
|
||||
"artemisAddress" to freeLocalHostAndPort().toString(),
|
||||
"p2pAddress" to freeLocalHostAndPort().toString(),
|
||||
"rpcAddress" to freeLocalHostAndPort().toString(),
|
||||
"extraAdvertisedServiceIds" to advertisedServices.map { it.toString() },
|
||||
"rpcUsers" to rpcUsers.map {
|
||||
mapOf(
|
||||
@ -141,4 +142,4 @@ abstract class NodeBasedTest {
|
||||
}
|
||||
return node
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,14 +24,14 @@ import kotlin.concurrent.thread
|
||||
* This is a bare-bones node which can only send and receive messages. It doesn't register with a network map service or
|
||||
* any other such task that would make it functionable in a network and thus left to the user to do so manually.
|
||||
*/
|
||||
class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort()) : AutoCloseable {
|
||||
class SimpleNode(val config: NodeConfiguration, val address: HostAndPort = freeLocalHostAndPort(), rpcAddress: HostAndPort = freeLocalHostAndPort()) : AutoCloseable {
|
||||
|
||||
private val databaseWithCloseable: Pair<Closeable, Database> = configureDatabase(config.dataSourceProperties)
|
||||
val database: Database get() = databaseWithCloseable.second
|
||||
val userService = RPCUserServiceImpl(config)
|
||||
val identity: KeyPair = generateKeyPair()
|
||||
val executor = ServiceAffinityExecutor(config.myLegalName, 1)
|
||||
val broker = ArtemisMessagingServer(config, address, InMemoryNetworkMapCache(), userService)
|
||||
val broker = ArtemisMessagingServer(config, address, rpcAddress, InMemoryNetworkMapCache(), userService)
|
||||
val networkMapRegistrationFuture: SettableFuture<Unit> = SettableFuture.create<Unit>()
|
||||
val net = databaseTransaction(database) {
|
||||
NodeMessagingClient(
|
||||
|
@ -14,7 +14,6 @@ import net.corda.client.model.Models
|
||||
import net.corda.client.model.observableValue
|
||||
import net.corda.core.contracts.GBP
|
||||
import net.corda.core.contracts.USD
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.explorer.model.CordaViewModel
|
||||
@ -28,7 +27,6 @@ import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||
import net.corda.node.driver.PortAllocation
|
||||
import net.corda.node.driver.driver
|
||||
import net.corda.node.services.User
|
||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||
import net.corda.node.services.startFlowPermission
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import org.apache.commons.lang.SystemUtils
|
||||
@ -141,7 +139,7 @@ fun main(args: Array<String>) {
|
||||
val issuerNodeUSD = issuerUSD.get()
|
||||
|
||||
arrayOf(notaryNode, aliceNode, bobNode, issuerNodeGBP, issuerNodeUSD).forEach {
|
||||
println("${it.nodeInfo.legalIdentity} started on ${ArtemisMessagingComponent.toHostAndPort(it.nodeInfo.address)}")
|
||||
println("${it.nodeInfo.legalIdentity} started on ${it.configuration.rpcAddress}")
|
||||
}
|
||||
|
||||
val parser = OptionParser("S")
|
||||
|
@ -30,9 +30,6 @@ class SettingsModel(path: Path = Paths.get("conf")) : Component(), Observable {
|
||||
private var username: String by config
|
||||
private var reportingCurrency: Currency by config
|
||||
private var fullscreen: Boolean by config
|
||||
private var certificatesDir: Path by config
|
||||
private var keyStorePassword: String by config
|
||||
private var trustStorePassword: String by config
|
||||
|
||||
// Create observable Properties.
|
||||
val reportingCurrencyProperty = writableConfigProperty(SettingsModel::reportingCurrency)
|
||||
@ -41,10 +38,6 @@ class SettingsModel(path: Path = Paths.get("conf")) : Component(), Observable {
|
||||
val portProperty = writableConfigProperty(SettingsModel::port)
|
||||
val usernameProperty = writableConfigProperty(SettingsModel::username)
|
||||
val fullscreenProperty = writableConfigProperty(SettingsModel::fullscreen)
|
||||
val certificatesDirProperty = writableConfigProperty(SettingsModel::certificatesDir)
|
||||
// TODO : We should encrypt all passwords in config file.
|
||||
val keyStorePasswordProperty = writableConfigProperty(SettingsModel::keyStorePassword)
|
||||
val trustStorePasswordProperty = writableConfigProperty(SettingsModel::trustStorePassword)
|
||||
|
||||
init {
|
||||
load()
|
||||
|
@ -5,16 +5,16 @@ import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
|
||||
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIconView
|
||||
import javafx.beans.property.SimpleIntegerProperty
|
||||
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.objectProperty
|
||||
import net.corda.core.exists
|
||||
import net.corda.explorer.model.SettingsModel
|
||||
import net.corda.node.services.config.SSLConfiguration
|
||||
import net.corda.node.services.config.configureTestSSL
|
||||
import org.controlsfx.dialog.ExceptionDialog
|
||||
import tornadofx.*
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class LoginView : View() {
|
||||
@ -26,7 +26,6 @@ class LoginView : View() {
|
||||
private val passwordTextField by fxid<PasswordField>()
|
||||
private val rememberMeCheckBox by fxid<CheckBox>()
|
||||
private val fullscreenCheckBox by fxid<CheckBox>()
|
||||
private val certificateButton by fxid<Button>()
|
||||
private val portProperty = SimpleIntegerProperty()
|
||||
|
||||
private val rememberMe by objectProperty(SettingsModel::rememberMeProperty)
|
||||
@ -34,9 +33,6 @@ class LoginView : View() {
|
||||
private val host by objectProperty(SettingsModel::hostProperty)
|
||||
private val port by objectProperty(SettingsModel::portProperty)
|
||||
private val fullscreen by objectProperty(SettingsModel::fullscreenProperty)
|
||||
private val certificatesDir by objectProperty(SettingsModel::certificatesDirProperty)
|
||||
private val keyStorePasswordProperty by objectProperty(SettingsModel::keyStorePasswordProperty)
|
||||
private val trustStorePasswordProperty by objectProperty(SettingsModel::trustStorePasswordProperty)
|
||||
|
||||
fun login() {
|
||||
val status = Dialog<LoginStatus>().apply {
|
||||
@ -46,7 +42,7 @@ class LoginView : View() {
|
||||
ButtonBar.ButtonData.OK_DONE -> try {
|
||||
root.isDisable = true
|
||||
// TODO : Run this async to avoid UI lockup.
|
||||
getModel<NodeMonitorModel>().register(HostAndPort.fromParts(hostTextField.text, portProperty.value), configureSSL(), usernameTextField.text, passwordTextField.text)
|
||||
getModel<NodeMonitorModel>().register(HostAndPort.fromParts(hostTextField.text, portProperty.value), usernameTextField.text, passwordTextField.text)
|
||||
if (!rememberMe.value) {
|
||||
username.value = ""
|
||||
host.value = ""
|
||||
@ -79,18 +75,6 @@ class LoginView : View() {
|
||||
if (status != LoginStatus.loggedIn) login()
|
||||
}
|
||||
|
||||
private fun configureSSL(): SSLConfiguration {
|
||||
val sslConfig = object : SSLConfiguration {
|
||||
override val certificatesDirectory: Path get() = certificatesDir.get()
|
||||
override val keyStorePassword: String get() = keyStorePasswordProperty.get()
|
||||
override val trustStorePassword: String get() = trustStorePasswordProperty.get()
|
||||
}
|
||||
// TODO : Don't use dev certificates.
|
||||
return if (sslConfig.keyStoreFile.exists()) sslConfig else configureTestSSL().apply {
|
||||
alert(Alert.AlertType.WARNING, "", "KeyStore not found in certificates directory.\nDEV certificates will be used by default.")
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// Restrict text field to Integer only.
|
||||
portTextField.textFormatter = intFormatter().apply { portProperty.bind(this.valueProperty()) }
|
||||
@ -99,44 +83,6 @@ class LoginView : View() {
|
||||
usernameTextField.textProperty().bindBidirectional(username)
|
||||
hostTextField.textProperty().bindBidirectional(host)
|
||||
portTextField.textProperty().bindBidirectional(port)
|
||||
certificateButton.setOnAction {
|
||||
Dialog<ButtonType>().apply {
|
||||
title = "Certificates Settings"
|
||||
initOwner(root.scene.window)
|
||||
dialogPane.content = gridpane {
|
||||
vgap = 10.0
|
||||
hgap = 5.0
|
||||
row("Certificates Directory :") {
|
||||
textfield {
|
||||
prefWidth = 400.0
|
||||
textProperty().bind(certificatesDir.map(Path::toString))
|
||||
isEditable = false
|
||||
}
|
||||
button {
|
||||
graphic = FontAwesomeIconView(FontAwesomeIcon.FOLDER_OPEN_ALT)
|
||||
maxHeight = Double.MAX_VALUE
|
||||
setOnAction {
|
||||
chooseDirectory(owner = dialogPane.scene.window) {
|
||||
initialDirectoryProperty().bind(certificatesDir.map(Path::toFile))
|
||||
}?.let {
|
||||
certificatesDir.set(it.toPath())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
row("KeyStore Password :") { passwordfield(keyStorePasswordProperty) }
|
||||
row("TrustStore Password :") { passwordfield(trustStorePasswordProperty) }
|
||||
}
|
||||
dialogPane.buttonTypes.addAll(ButtonType.APPLY, ButtonType.CANCEL)
|
||||
}.showAndWait().get().let {
|
||||
when (it) {
|
||||
ButtonType.APPLY -> getModel<SettingsModel>().commit()
|
||||
// Discard changes.
|
||||
else -> getModel<SettingsModel>().load()
|
||||
}
|
||||
}
|
||||
}
|
||||
certificateButton.tooltip("Certificate Configuration")
|
||||
}
|
||||
|
||||
private enum class LoginStatus {
|
||||
|
@ -26,23 +26,15 @@
|
||||
<Label text="Corda Node :" GridPane.halignment="RIGHT"/>
|
||||
<TextField fx:id="hostTextField" promptText="Host" GridPane.columnIndex="1"/>
|
||||
<TextField fx:id="portTextField" prefWidth="100" promptText="Port" GridPane.columnIndex="2"/>
|
||||
<Button id="certificateButton" fx:id="certificateButton" GridPane.columnIndex="3" styleClass="certificateButton">
|
||||
<padding>
|
||||
<Insets right="6"/>
|
||||
</padding>
|
||||
<graphic>
|
||||
<FontAwesomeIconView styleClass="certificateIcon" glyphName="LOCK" glyphSize="20"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Label text="Username :" GridPane.rowIndex="1" GridPane.halignment="RIGHT"/>
|
||||
<TextField fx:id="usernameTextField" promptText="Username" GridPane.columnIndex="1"
|
||||
GridPane.columnSpan="3" GridPane.rowIndex="1"/>
|
||||
GridPane.columnSpan="2" GridPane.rowIndex="1"/>
|
||||
|
||||
<Label text="Password :" GridPane.rowIndex="2" GridPane.halignment="RIGHT"/>
|
||||
<PasswordField fx:id="passwordTextField" promptText="Password" GridPane.columnIndex="1"
|
||||
GridPane.columnSpan="3" GridPane.rowIndex="2"/>
|
||||
GridPane.columnSpan="2" GridPane.rowIndex="2"/>
|
||||
|
||||
<HBox spacing="20" GridPane.columnIndex="1" GridPane.rowIndex="3" GridPane.columnSpan="3">
|
||||
<HBox spacing="20" GridPane.columnIndex="1" GridPane.rowIndex="3" GridPane.columnSpan="2">
|
||||
<CheckBox fx:id="rememberMeCheckBox" text="Remember me"/>
|
||||
<CheckBox fx:id="fullscreenCheckBox" text="Fullscreen mode"/>
|
||||
</HBox>
|
||||
|
@ -71,8 +71,6 @@ class ConnectionManager(private val username: String, private val jSch: JSch) {
|
||||
nodeHost: String,
|
||||
remoteMessagingPort: Int,
|
||||
localTunnelAddress: HostAndPort,
|
||||
certificatesBaseDirectory: Path,
|
||||
remoteCertificatesDirectory: Path,
|
||||
rpcUsername: String,
|
||||
rpcPassword: String
|
||||
): NodeConnection {
|
||||
@ -87,19 +85,7 @@ class ConnectionManager(private val username: String, private val jSch: JSch) {
|
||||
session.setPortForwardingL(localTunnelAddress.port, localTunnelAddress.hostText, remoteMessagingPort)
|
||||
log.info("Tunnel created!")
|
||||
|
||||
val certificatesDirectory = certificatesBaseDirectory / nodeHost
|
||||
val sslKeyStoreFileName = "sslkeystore.jks"
|
||||
val trustStoreFileName = "truststore.jks"
|
||||
log.info("Copying server certificates to $certificatesDirectory")
|
||||
certificatesDirectory.createDirectories()
|
||||
val channel = session.openChannel("sftp") as ChannelSftp
|
||||
channel.connect()
|
||||
channel.get((remoteCertificatesDirectory / sslKeyStoreFileName).toString(), certificatesDirectory.toString())
|
||||
channel.get((remoteCertificatesDirectory / trustStoreFileName).toString(), certificatesDirectory.toString())
|
||||
channel.disconnect()
|
||||
log.info("Certificates copied!")
|
||||
|
||||
val connection = NodeConnection(nodeHost, session, localTunnelAddress, certificatesDirectory, rpcUsername, rpcPassword)
|
||||
val connection = NodeConnection(nodeHost, session, localTunnelAddress, rpcUsername, rpcPassword)
|
||||
connection.startClient()
|
||||
return connection
|
||||
}
|
||||
@ -122,7 +108,6 @@ fun <A> connectToNodes(
|
||||
nodeHostsAndCertificatesPaths: List<Pair<String, Path>>,
|
||||
remoteMessagingPort: Int,
|
||||
tunnelPortAllocation: PortAllocation,
|
||||
certificatesBaseDirectory: Path,
|
||||
rpcUsername: String,
|
||||
rpcPassword: String,
|
||||
withConnections: (List<NodeConnection>) -> A
|
||||
@ -133,8 +118,6 @@ fun <A> connectToNodes(
|
||||
nodeHost = nodeHostAndCertificatesPath.first,
|
||||
remoteMessagingPort = remoteMessagingPort,
|
||||
localTunnelAddress = tunnelPortAllocation.nextHostAndPort(),
|
||||
certificatesBaseDirectory = certificatesBaseDirectory,
|
||||
remoteCertificatesDirectory = nodeHostAndCertificatesPath.second,
|
||||
rpcUsername = rpcUsername,
|
||||
rpcPassword = rpcPassword
|
||||
)
|
||||
@ -157,17 +140,9 @@ class NodeConnection(
|
||||
val hostName: String,
|
||||
private val jSchSession: Session,
|
||||
private val localTunnelAddress: HostAndPort,
|
||||
private val certificatesDirectory: Path,
|
||||
private val rpcUsername: String,
|
||||
private val rpcPassword: String
|
||||
) : Closeable {
|
||||
|
||||
private val sslConfig = object : SSLConfiguration {
|
||||
override val certificatesDirectory = this@NodeConnection.certificatesDirectory
|
||||
override val keyStorePassword: String get() = "cordacadevpass"
|
||||
override val trustStorePassword: String get() = "trustpass"
|
||||
}
|
||||
|
||||
private var client: CordaRPCClient? = null
|
||||
private var _proxy: CordaRPCOps? = null
|
||||
val proxy: CordaRPCOps get() = _proxy ?: throw IllegalStateException("proxy requested, but the client is not running")
|
||||
@ -202,7 +177,7 @@ class NodeConnection(
|
||||
return action()
|
||||
} finally {
|
||||
log.info("Starting new RPC proxy to $hostName, tunnel at $localTunnelAddress")
|
||||
val newClient = CordaRPCClient(localTunnelAddress, sslConfig)
|
||||
val newClient = CordaRPCClient(localTunnelAddress)
|
||||
// TODO expose these somehow?
|
||||
newClient.start(rpcUsername, rpcPassword)
|
||||
val newProxy = newClient.proxy()
|
||||
@ -213,7 +188,7 @@ class NodeConnection(
|
||||
|
||||
fun startClient() {
|
||||
log.info("Creating RPC proxy to $hostName, tunnel at $localTunnelAddress")
|
||||
val client = CordaRPCClient(localTunnelAddress, sslConfig)
|
||||
val client = CordaRPCClient(localTunnelAddress)
|
||||
client.start(rpcUsername, rpcPassword)
|
||||
val proxy = client.proxy()
|
||||
log.info("Proxy created")
|
||||
|
@ -163,7 +163,6 @@ fun runLoadTests(configuration: LoadTestConfiguration, tests: List<Pair<LoadTest
|
||||
configuration.nodeHosts.map { it to configuration.remoteNodeDirectory / "certificates" },
|
||||
configuration.remoteMessagingPort,
|
||||
PortAllocation.Incremental(configuration.localTunnelStartingPort),
|
||||
configuration.localCertificatesBaseDirectory,
|
||||
configuration.rpcUsername,
|
||||
configuration.rpcPassword
|
||||
) { connections ->
|
||||
|
@ -3,7 +3,7 @@
|
||||
localCertificatesBaseDirectory = "build/load-test/certificates"
|
||||
localTunnelStartingPort = 10000
|
||||
remoteNodeDirectory = "/opt/corda"
|
||||
remoteMessagingPort = 10002
|
||||
remoteMessagingPort = 10003
|
||||
remoteSystemdServiceName = "corda"
|
||||
rpcUsername = "corda"
|
||||
rpcPassword = "rgb"
|
||||
rpcPassword = "rgb"
|
||||
|
Loading…
Reference in New Issue
Block a user