diff --git a/.ci/dev/regression/Jenkinsfile b/.ci/dev/regression/Jenkinsfile index c9675d84f7..b41c57aaff 100644 --- a/.ci/dev/regression/Jenkinsfile +++ b/.ci/dev/regression/Jenkinsfile @@ -61,6 +61,7 @@ String COMMON_GRADLE_PARAMS = [ '--info', '-Pcompilation.warningsAsErrors=false', '-Ptests.failFast=true', + '-DexcludeShell', ].join(' ') pipeline { @@ -86,6 +87,18 @@ pipeline { parallelsAlwaysFailFast() timeout(time: 6, unit: 'HOURS') timestamps() + office365ConnectorWebhooks([[ + name : "Corda 4 Jenkins Connector", + notifyBackToNormal : true, + startNotification : false, + notifyFailure : true, + notifySuccess : true, + notifyNotBuilt : false, + notifyAborted : false, + notifyRepeatedFailure: true, + notifyUnstable : true, + url : "${teamsWebHookURL}" + ]]) } parameters { @@ -295,7 +308,7 @@ pipeline { rtGradleRun( usesPlugin: true, useWrapper: true, - switches: '-s --info', + switches: '-s --info -DpublishApiDocs', tasks: 'artifactoryPublish', deployerId: 'deployer', buildName: env.ARTIFACTORY_BUILD_NAME diff --git a/build.gradle b/build.gradle index ae3e8f196e..3498bcdd30 100644 --- a/build.gradle +++ b/build.gradle @@ -61,6 +61,7 @@ buildscript { ext.asm_version = constants.getProperty("asmVersion") ext.artemis_version = constants.getProperty("artemisVersion") ext.jackson_version = constants.getProperty("jacksonVersion") + ext.jackson_kotlin_version = constants.getProperty("jacksonKotlinVersion") ext.jetty_version = constants.getProperty("jettyVersion") ext.jersey_version = constants.getProperty("jerseyVersion") ext.servlet_version = constants.getProperty("servletVersion") @@ -413,6 +414,12 @@ allprojects { includeGroup 'com.github.detro' } } + maven { + url "${artifactory_contextUrl}/corda-releases" + content { + includeModule('net.corda', 'corda-shell') + } + } mavenCentral() jcenter() } diff --git a/client/jackson/build.gradle b/client/jackson/build.gradle index e586479b80..b86798a8b3 100644 --- a/client/jackson/build.gradle +++ b/client/jackson/build.gradle @@ -9,7 +9,9 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // Jackson and its plugins: parsing to/from JSON and other textual formats. - compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version" + compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") { + exclude module: "jackson-databind" + } // Yaml is useful for parsing strings to method calls. compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" // This adds support for java.time types. diff --git a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt index 95f6f3e03c..46d7c105f3 100644 --- a/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt +++ b/client/jackson/src/main/kotlin/net/corda/client/jackson/JacksonSupport.kt @@ -2,10 +2,24 @@ package net.corda.client.jackson import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.core.* -import com.fasterxml.jackson.databind.* +import com.fasterxml.jackson.core.JsonFactory +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParseException +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.core.JsonToken +import com.fasterxml.jackson.databind.BeanDescription +import com.fasterxml.jackson.databind.DeserializationConfig +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.JsonSerializer +import com.fasterxml.jackson.databind.Module +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.databind.cfg.ConstructorDetector import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier import com.fasterxml.jackson.databind.deser.std.NumberDeserializers import com.fasterxml.jackson.databind.node.ObjectNode @@ -21,9 +35,21 @@ import net.corda.core.DoNotImplement import net.corda.core.contracts.Amount import net.corda.core.contracts.ContractState import net.corda.core.contracts.StateRef -import net.corda.core.crypto.* -import net.corda.core.identity.* -import net.corda.core.internal.* +import net.corda.core.crypto.Base58 +import net.corda.core.crypto.MerkleTree +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.TransactionSignature +import net.corda.core.crypto.toStringShort +import net.corda.core.identity.AbstractParty +import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name +import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate +import net.corda.core.internal.CertRole +import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.isStatic +import net.corda.core.internal.kotlinObjectInstance +import net.corda.core.internal.uncheckedCast import net.corda.core.messaging.CordaRPCOps import net.corda.core.node.NodeInfo import net.corda.core.node.services.IdentityService @@ -179,6 +205,8 @@ object JacksonSupport { addMixIn(X500Principal::class.java, X500PrincipalMixin::class.java) addMixIn(X509Certificate::class.java, X509CertificateMixin::class.java) addMixIn(CertPath::class.java, CertPathMixin::class.java) + + setConstructorDetector(ConstructorDetector.DEFAULT.withAllowJDKTypeConstructors(true)) } } diff --git a/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt b/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt index 17e98ffd22..24e3efd707 100644 --- a/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt +++ b/client/jackson/src/main/kotlin/net/corda/client/jackson/internal/CordaModule.kt @@ -2,16 +2,30 @@ package net.corda.client.jackson.internal -import com.fasterxml.jackson.annotation.* import com.fasterxml.jackson.annotation.JsonAutoDetect.Value import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility +import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonCreator.Mode.DISABLED +import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonInclude.Include +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.fasterxml.jackson.annotation.JsonValue import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.core.JsonParseException import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.JsonToken -import com.fasterxml.jackson.databind.* +import com.fasterxml.jackson.databind.BeanDescription +import com.fasterxml.jackson.databind.BeanProperty +import com.fasterxml.jackson.databind.DeserializationConfig +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JavaType +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.JsonSerializer +import com.fasterxml.jackson.databind.Module +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationConfig +import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.databind.cfg.MapperConfig @@ -19,6 +33,7 @@ import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier import com.fasterxml.jackson.databind.deser.ContextualDeserializer import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer +import com.fasterxml.jackson.databind.introspect.AccessorNamingStrategy import com.fasterxml.jackson.databind.introspect.AnnotatedClass import com.fasterxml.jackson.databind.introspect.BasicClassIntrospector import com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector @@ -31,12 +46,30 @@ import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer import com.fasterxml.jackson.databind.ser.std.UUIDSerializer import com.google.common.primitives.Booleans import net.corda.client.jackson.JacksonSupport -import net.corda.core.contracts.* -import net.corda.core.crypto.* +import net.corda.core.contracts.Amount +import net.corda.core.contracts.AttachmentConstraint +import net.corda.core.contracts.Command +import net.corda.core.contracts.CommandData +import net.corda.core.contracts.ContractState +import net.corda.core.contracts.PrivacySalt +import net.corda.core.contracts.StateRef +import net.corda.core.contracts.TimeWindow +import net.corda.core.contracts.TransactionState +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.DigestService +import net.corda.core.crypto.DigitalSignature import net.corda.core.crypto.PartialMerkleTree.PartialTree +import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash.Companion.SHA2_256 +import net.corda.core.crypto.SignatureMetadata +import net.corda.core.crypto.SignatureScheme +import net.corda.core.crypto.TransactionSignature import net.corda.core.flows.StateMachineRunId -import net.corda.core.identity.* +import net.corda.core.identity.AbstractParty +import net.corda.core.identity.AnonymousParty +import net.corda.core.identity.CordaX500Name +import net.corda.core.identity.Party +import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.DigitalSignatureWithCert import net.corda.core.internal.createComponentGroups import net.corda.core.node.NodeInfo @@ -44,7 +77,12 @@ import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializedBytes import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize -import net.corda.core.transactions.* +import net.corda.core.transactions.ContractUpgradeFilteredTransaction +import net.corda.core.transactions.ContractUpgradeWireTransaction +import net.corda.core.transactions.FilteredTransaction +import net.corda.core.transactions.NotaryChangeWireTransaction +import net.corda.core.transactions.SignedTransaction +import net.corda.core.transactions.WireTransaction import net.corda.core.utilities.ByteSequence import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.parseAsHex @@ -117,6 +155,14 @@ private class CordaSerializableClassIntrospector(private val context: Module.Set } return super.constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix) } + + override fun constructPropertyCollector(config: MapperConfig<*>?, classDef: AnnotatedClass?, type: JavaType, forSerialization: Boolean, accNaming: AccessorNamingStrategy?): POJOPropertiesCollector { + if (hasCordaSerializable(type.rawClass)) { + // Adjust the field visibility of CordaSerializable classes on the fly as they are encountered. + context.configOverride(type.rawClass).visibility = Value.defaultVisibility().withFieldVisibility(Visibility.ANY) + } + return super.constructPropertyCollector(config, classDef, type, forSerialization, accNaming) + } } private class CordaSerializableBeanSerializerModifier : BeanSerializerModifier() { diff --git a/client/jfx/build.gradle b/client/jfx/build.gradle index d8a1b514ec..06c1bbbd93 100644 --- a/client/jfx/build.gradle +++ b/client/jfx/build.gradle @@ -55,7 +55,9 @@ dependencies { // TODO: remove the forced update of commons-collections and beanutils when artemis updates them compile "org.apache.commons:commons-collections4:${commons_collections_version}" compile "commons-beanutils:commons-beanutils:${beanutils_version}" - compile "org.apache.activemq:artemis-core-client:${artemis_version}" + compile("org.apache.activemq:artemis-core-client:${artemis_version}") { + exclude group: 'org.jgroups', module: 'jgroups' + } // Unit testing helpers. testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" diff --git a/constants.properties b/constants.properties index 94dad22d7c..0aedd166b9 100644 --- a/constants.properties +++ b/constants.properties @@ -46,7 +46,8 @@ capsuleVersion=1.0.3 asmVersion=7.1 artemisVersion=2.19.1 # TODO Upgrade Jackson only when corda is using kotlin 1.3.10 -jacksonVersion=2.9.7 +jacksonVersion=2.13.1 +jacksonKotlinVersion=2.9.7 jettyVersion=9.4.19.v20190610 jerseyVersion=2.25 servletVersion=4.0.1 diff --git a/docker/src/docker/Dockerfile-debug b/docker/src/docker/Dockerfile-debug index b961b4570d..a1175c989c 100644 --- a/docker/src/docker/Dockerfile-debug +++ b/docker/src/docker/Dockerfile-debug @@ -2,6 +2,7 @@ FROM azul/zulu-openjdk:8u312 ## Add packages, clean cache, create dirs, create corda user and change ownership RUN apt-get update && \ + apt-mark hold zulu8-jdk && \ apt-get -y upgrade && \ apt-get -y install bash curl unzip netstat lsof telnet netcat && \ rm -rf /var/lib/apt/lists/* && \ diff --git a/node-api/build.gradle b/node-api/build.gradle index b47bc040be..7299cfa23e 100644 --- a/node-api/build.gradle +++ b/node-api/build.gradle @@ -17,7 +17,9 @@ dependencies { // TODO: remove the forced update of commons-collections and beanutils when artemis updates them compile "org.apache.commons:commons-collections4:${commons_collections_version}" compile "commons-beanutils:commons-beanutils:${beanutils_version}" - compile "org.apache.activemq:artemis-core-client:${artemis_version}" + compile("org.apache.activemq:artemis-core-client:${artemis_version}") { + exclude group: 'org.jgroups', module: 'jgroups' + } compile "org.apache.activemq:artemis-commons:${artemis_version}" compile "io.netty:netty-handler-proxy:$netty_version" @@ -62,6 +64,7 @@ dependencies { compile ("org.apache.activemq:artemis-amqp-protocol:${artemis_version}") { // Gains our proton-j version from core module. exclude group: 'org.apache.qpid', module: 'proton-j' + exclude group: 'org.jgroups', module: 'jgroups' } } diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_ec.jks b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_ec.jks index 41bf8579a3..f0a6921cff 100644 Binary files a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_ec.jks and b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_ec.jks differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_rsa.jks b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_rsa.jks index d6828b2390..87224d4727 100644 Binary files a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_rsa.jks and b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/bridge_rsa.jks differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_ec.jks b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_ec.jks index 7deeda8119..bd7f263226 100644 Binary files a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_ec.jks and b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_ec.jks differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_rsa.jks b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_rsa.jks index 6eddf4d4b1..737826a534 100644 Binary files a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_rsa.jks and b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/float_rsa.jks differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/gencerts.sh b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/gencerts.sh new file mode 100755 index 0000000000..f676de80d9 --- /dev/null +++ b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/gencerts.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# These jks files have been produced with KeyTool using commands from V3 Float/Bridge setup here: +# https://docs.corda.r3.com/bridge-configuration-file.html#complete-example + +# More specifically the following script can be run on mac to generate the files needed. +# Trust Root with EC algo +keytool -genkeypair -keyalg EC -keysize 256 -alias floatroot -validity 3650 -dname "CN=Float Root,O=Local Only,L=London,C=GB" -ext bc:ca:true,pathlen:1 -keystore floatca.jks -storepass capass -keypass cakeypass + +# Bridge and Float with EC +keytool -genkeypair -keyalg EC -keysize 256 -alias bridgecert -validity 3650 -dname "CN=Bridge Local,O=Local Only,L=London,C=GB" -ext bc:ca:false -keystore bridge_ec.jks -storepass bridgepass -keypass bridgepass +keytool -genkeypair -keyalg EC -keysize 256 -alias floatcert -validity 3650 -dname "CN=Float Local,O=Local Only,L=London,C=GB" -ext bc:ca:false -keystore float_ec.jks -storepass floatpass -keypass floatpass + +# Bridge and Float with RSA +keytool -genkeypair -keyalg RSA -keysize 1024 -alias bridgecert -validity 3650 -dname "CN=Bridge Local,O=Local Only,L=London,C=GB" -ext bc:ca:false -keystore bridge_rsa.jks -storepass bridgepass -keypass bridgepass +keytool -genkeypair -keyalg RSA -keysize 1024 -alias floatcert -validity 3650 -dname "CN=Float Local,O=Local Only,L=London,C=GB" -ext bc:ca:false -keystore float_rsa.jks -storepass floatpass -keypass floatpass + +# Export Trust root for subsequent chaining +keytool -exportcert -rfc -alias floatroot -keystore floatca.jks -storepass capass -keypass cakeypass > root.pem +keytool -importcert -noprompt -file root.pem -alias root -keystore trust.jks -storepass trustpass + +# Create a chain for EC Bridge +keytool -certreq -alias bridgecert -keystore bridge_ec.jks -storepass bridgepass -keypass bridgepass |keytool -gencert -validity 3650 -ext ku:c=dig,keyEncipherment -ext: eku:true=serverAuth,clientAuth -rfc -keystore floatca.jks -alias floatroot -storepass capass -keypass cakeypass > bridge_ec.pem +cat root.pem bridge_ec.pem >> bridgechain_ec.pem +keytool -importcert -noprompt -file bridgechain_ec.pem -alias bridgecert -keystore bridge_ec.jks -storepass bridgepass -keypass bridgepass + +# Create a chain for RSA Bridge +keytool -certreq -alias bridgecert -keystore bridge_rsa.jks -storepass bridgepass -keypass bridgepass |keytool -gencert -validity 3650 -ext ku:c=dig,keyEncipherment -ext: eku:true=serverAuth,clientAuth -rfc -keystore floatca.jks -alias floatroot -storepass capass -keypass cakeypass > bridge_rsa.pem +cat root.pem bridge_rsa.pem >> bridgechain_rsa.pem +keytool -importcert -noprompt -file bridgechain_rsa.pem -alias bridgecert -keystore bridge_rsa.jks -storepass bridgepass -keypass bridgepass + +# Create a chain for EC Float +keytool -certreq -alias floatcert -keystore float_ec.jks -storepass floatpass -keypass floatpass |keytool -gencert -validity 3650 -ext ku:c=dig,keyEncipherment -ext: eku::true=serverAuth,clientAuth -rfc -keystore floatca.jks -alias floatroot -storepass capass -keypass cakeypass > float_ec.pem +cat root.pem float_ec.pem >> floatchain_ec.pem +keytool -importcert -noprompt -file floatchain_ec.pem -alias floatcert -keystore float_ec.jks -storepass floatpass -keypass floatpass + +# Create a chain for RSA Float +keytool -certreq -alias floatcert -keystore float_rsa.jks -storepass floatpass -keypass floatpass |keytool -gencert -validity 3650 -ext ku:c=dig,keyEncipherment -ext: eku::true=serverAuth,clientAuth -rfc -keystore floatca.jks -alias floatroot -storepass capass -keypass cakeypass > float_rsa.pem +cat root.pem float_rsa.pem >> floatchain_rsa.pem +keytool -importcert -noprompt -file floatchain_rsa.pem -alias floatcert -keystore float_rsa.jks -storepass floatpass -keypass floatpass diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/trust.jks b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/trust.jks index ea5b53b445..1252f7002a 100644 Binary files a/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/trust.jks and b/node-api/src/test/resources/net/corda/nodeapi/internal/crypto/keystores/trust.jks differ diff --git a/node/build.gradle b/node/build.gradle index 9b82652aeb..0b4a47213d 100644 --- a/node/build.gradle +++ b/node/build.gradle @@ -127,11 +127,17 @@ dependencies { // TODO: remove the forced update of commons-collections and beanutils when artemis updates them compile "org.apache.commons:commons-collections4:${commons_collections_version}" compile "commons-beanutils:commons-beanutils:${beanutils_version}" - compile "org.apache.activemq:artemis-server:${artemis_version}" - compile "org.apache.activemq:artemis-core-client:${artemis_version}" + compile("org.apache.activemq:artemis-server:${artemis_version}") { + exclude group: 'org.apache.commons', module: 'commons-dbcp2' + exclude group: 'org.jgroups', module: 'jgroups' + } + compile("org.apache.activemq:artemis-core-client:${artemis_version}") { + exclude group: 'org.jgroups', module: 'jgroups' + } runtime("org.apache.activemq:artemis-amqp-protocol:${artemis_version}") { // Gains our proton-j version from core module. exclude group: 'org.apache.qpid', module: 'proton-j' + exclude group: 'org.jgroups', module: 'jgroups' } // Manifests: for reading stuff from the manifest file diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 82eacfcbf4..2f2479c139 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -690,9 +690,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration, val isShellStarted = InteractiveShell.startShellIfInstalled(configuration, cordappLoader) configuration.sshd?.port?.let { if (isShellStarted) { - log.info("Binding Shell SSHD server on port $it.") + Node.printBasicNodeInfo("SSH server listening on port", configuration.sshd!!.port.toString()) + log.info("SSH server listening on port: $it.") } else { - log.info("SSH port defined but corda-shell is not installed in node's drivers directory") + Node.printBasicNodeInfo( + "SSH server not started. SSH port is defined but the corda-shell is not installed in node's drivers directory" + ) + log.info("SSH server not started. SSH port is defined but the corda-shell is not installed in node's drivers directory") } } } diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 0e90920616..1772210e56 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -48,7 +48,6 @@ import net.corda.node.internal.subcommands.ValidateConfigurationCli.Companion.lo import net.corda.node.internal.subcommands.ValidateConfigurationCli.Companion.logRawConfig import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.shouldStartLocalShell -import net.corda.node.services.config.shouldStartSSHDaemon import net.corda.node.utilities.registration.NodeRegistrationException import net.corda.nodeapi.internal.JVMAgentUtilities import net.corda.nodeapi.internal.addShutdownHook @@ -263,19 +262,8 @@ open class NodeStartup : NodeStartupLogging { Node.printBasicNodeInfo("Node for \"$name\" started up and registered in $elapsed sec") // Don't start the shell if there's no console attached. - val isShellStarted = if (node.configuration.shouldStartLocalShell()) { + if (node.configuration.shouldStartLocalShell()) { InteractiveShell.runLocalShellIfInstalled(node::stop) - } else { - false - } - if (node.configuration.shouldStartSSHDaemon()) { - if (isShellStarted) { - Node.printBasicNodeInfo("SSH server listening on port", node.configuration.sshd!!.port.toString()) - } else { - Node.printBasicNodeInfo( - "SSH server not started. SSH port is defined but the corda-shell is not installed in node's drivers directory" - ) - } } }, { th -> diff --git a/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt b/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt index c77e39cec0..2bed926da5 100644 --- a/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt +++ b/node/src/main/kotlin/net/corda/node/services/api/IdentityServiceInternal.kt @@ -15,4 +15,6 @@ interface IdentityServiceInternal : IdentityService { fun verifyAndRegisterNewRandomIdentity(identity: PartyAndCertificate) fun invalidateCaches(name: CordaX500Name) {} + + fun archiveNamedIdentity(name:String, publicKeyHash: String?) {} } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt index fb0137fbe2..2e10525141 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt @@ -378,7 +378,7 @@ class PersistentIdentityService(cacheFactory: NamedCacheFactory) : SingletonSeri return resultList.last().publicKeyHash } - private fun archiveNamedIdentity(name:String, publicKeyHash: String?) { + override fun archiveNamedIdentity(name:String, publicKeyHash: String?) { archiveIdentityExecutor.submit { database.transaction { val deleteQuery = session.criteriaBuilder.createCriteriaDelete(PersistentNetworkMapCache.PersistentPartyToPublicKeyHash::class.java) diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt index eb79a58302..2749f83c5d 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt @@ -310,7 +310,7 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory, synchronized(_changed) { database.transaction { removeInfoDB(session, node) - archiveNamedIdentity(session, node) + archiveNamedIdentity(node) changePublisher.onNext(MapChange.Removed(node)) } } @@ -319,13 +319,9 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory, logger.debug { "Done removing node with info: $node" } } - private fun archiveNamedIdentity(session: Session, nodeInfo: NodeInfo) { + private fun archiveNamedIdentity(nodeInfo: NodeInfo) { nodeInfo.legalIdentities.forEach { party -> - val deleteQuery = session.criteriaBuilder.createCriteriaDelete(PersistentPartyToPublicKeyHash::class.java) - val queryRoot = deleteQuery.from(PersistentPartyToPublicKeyHash::class.java) - deleteQuery.where(session.criteriaBuilder.equal(queryRoot.get("name"), party.name.toString())) - session.createQuery(deleteQuery).executeUpdate() - session.save(PersistentPartyToPublicKeyHash(party.name.toString(), party.owningKey.toStringShort() )) + identityService.archiveNamedIdentity(party.name.toString(), party.owningKey.toStringShort()) } } @@ -457,7 +453,7 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory, logger.debug { "Number of node infos to be cleared: ${result.size}" } for (nodeInfo in result) { session.remove(nodeInfo) - archiveNamedIdentity(session, nodeInfo.toNodeInfo()) + archiveNamedIdentity(nodeInfo.toNodeInfo()) } } } diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt index e6aee94e7f..6ea173ef4d 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt @@ -88,6 +88,9 @@ class NodeAttachmentService @JvmOverloads constructor( while (true) { val cursor = jar.nextJarEntry ?: break + // Security check to stop directory traversal from filename entry + require(!(cursor.name.contains("../"))) { "Bad character in ${cursor.name}" } + require(!(cursor.name.contains("..\\"))) { "Bad character in ${cursor.name}" } if (manifestHasEntries && !allManifestEntries!!.remove(cursor.name)) extraFilesNotFoundInEntries.add(cursor) val entryPath = Paths.get(cursor.name) // Security check to stop zips trying to escape their rightful place. diff --git a/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt b/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt index 4e2e2a3153..a9aceab60b 100644 --- a/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/rpc/CheckpointDumperImpl.kt @@ -584,7 +584,7 @@ class CheckpointDumperImpl(private val checkpointStorage: CheckpointStorage, pri private object MapSerializer : JsonSerializer>() { override fun serialize(map: Map, gen: JsonGenerator, serializers: SerializerProvider) { - gen.writeStartArray(map.size) + gen.writeStartArray() map.forEach { (key, value) -> gen.jsonObject { writeObjectField("key", key) diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt index e419df5d01..7c52587a3f 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt @@ -46,14 +46,19 @@ import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Ignore import org.junit.Test +import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream +import java.io.InputStream import java.net.URL import java.nio.charset.StandardCharsets import java.nio.file.FileAlreadyExistsException import java.nio.file.FileSystem import java.nio.file.Path import java.util.* +import java.util.jar.JarEntry import java.util.jar.JarInputStream +import java.util.jar.JarOutputStream +import java.util.jar.Manifest import kotlin.streams.toList import kotlin.test.* @@ -788,6 +793,32 @@ class NodeAttachmentServiceTest { } } + @Test(timeout=300_000) + fun `attachments containing jar entries whose names expose malicious directory traversal are prevented`() { + + fun createJarWithJarEntryTraversalAttack(jarEntryName: String): InputStream { + val byteArrayOutputStream = ByteArrayOutputStream() + JarOutputStream(byteArrayOutputStream, Manifest()).apply { + putNextEntry(JarEntry(jarEntryName)) + write("some-text".toByteArray()) + closeEntry() + close() + } + return ByteArrayInputStream(byteArrayOutputStream.toByteArray()) + } + + val traversalAttackJarWin = createJarWithJarEntryTraversalAttack("..\\attack") + val traversalAttackJarUnix = createJarWithJarEntryTraversalAttack("../attack") + + assertFailsWith(IllegalArgumentException::class) { + NodeAttachmentService.checkIsAValidJAR(traversalAttackJarWin) + } + + assertFailsWith(IllegalArgumentException::class) { + NodeAttachmentService.checkIsAValidJAR(traversalAttackJarUnix) + } + } + @Test(timeout=300_000) fun `attachments can be queried by providing a intersection of signers using an EQUAL statement - EQUAL containing a single public key`() { SelfCleaningDir().use { file -> diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 0e6000cbe2..02fa732184 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -31,6 +31,9 @@ configurations { } dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" compile "javax.servlet:javax.servlet-api:${servlet_version}" diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index aa377a6cee..11d398ce8b 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -6,6 +6,9 @@ apply plugin: 'net.corda.plugins.cordapp' apply plugin: 'net.corda.plugins.cordformation' dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" // The bank of corda CorDapp depends upon Cash CorDapp features diff --git a/samples/cordapp-configuration/build.gradle b/samples/cordapp-configuration/build.gradle index 4c57c1b941..5f1155c184 100644 --- a/samples/cordapp-configuration/build.gradle +++ b/samples/cordapp-configuration/build.gradle @@ -3,6 +3,9 @@ apply plugin: 'idea' apply plugin: 'net.corda.plugins.cordformation' dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } runtimeOnly project(':node-api') // Cordformation needs a SLF4J implementation when executing the Network // Bootstrapper, but Log4J doesn't shutdown completely from within Gradle. diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index 700dd73dc4..0cf5896f9a 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -9,7 +9,8 @@ plugins { ext['artemis.version'] = "$artemis_version" ext['hibernate.version'] = "$hibernate_version" ext['selenium.version'] = "$selenium_version" -ext['jackson.version'] = "$jackson_version" +// Using jackson_kotlin_version here for JDK11 compatibility with kotlin 1.2.71 +ext['jackson.version'] = "$jackson_kotlin_version" ext['dropwizard-metrics.version'] = "$metrics_version" ext['mockito.version'] = "$mockito_version" diff --git a/samples/irs-demo/cordapp/build.gradle b/samples/irs-demo/cordapp/build.gradle index e46aea2330..71d0428949 100644 --- a/samples/irs-demo/cordapp/build.gradle +++ b/samples/irs-demo/cordapp/build.gradle @@ -27,6 +27,9 @@ cordapp { } dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } cordapp project(':finance:contracts') cordapp project(':finance:workflows') diff --git a/samples/irs-demo/cordapp/workflows-irs/build.gradle b/samples/irs-demo/cordapp/workflows-irs/build.gradle index ce09b2a803..ff88428b24 100644 --- a/samples/irs-demo/cordapp/workflows-irs/build.gradle +++ b/samples/irs-demo/cordapp/workflows-irs/build.gradle @@ -16,7 +16,7 @@ dependencies { cordaCompile project(':core') - compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version") + compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") // only included to control the `DemoClock` as part of the demo application // normally `:node` should not be depended on in any CorDapps diff --git a/samples/irs-demo/web/build.gradle b/samples/irs-demo/web/build.gradle index 8064af4347..b887d036cb 100644 --- a/samples/irs-demo/web/build.gradle +++ b/samples/irs-demo/web/build.gradle @@ -70,7 +70,7 @@ dependencies { } compile('org.springframework.boot:spring-boot-starter-log4j2') runtimeOnly("org.apache.logging.log4j:log4j-web:$log4j_version") - compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version") + compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version") compile project(":client:rpc") compile project(":client:jackson") compile project(":finance:workflows") diff --git a/samples/network-verifier/build.gradle b/samples/network-verifier/build.gradle index ab6d4d37a5..1cd1c9f4b8 100644 --- a/samples/network-verifier/build.gradle +++ b/samples/network-verifier/build.gradle @@ -12,6 +12,9 @@ cordapp { } dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } // Cordformation needs this for the Network Bootstrapper. runtimeOnly project(':node-api') diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle index 1cd9710a65..6f87b55b35 100644 --- a/samples/notary-demo/build.gradle +++ b/samples/notary-demo/build.gradle @@ -15,6 +15,9 @@ cordapp { } dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" cordaCompile project(':client:rpc') // Corda integration dependencies diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 7f2f3e17bc..0609747f93 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -26,8 +26,10 @@ configurations { } dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } cordaCompile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - // The SIMM demo CorDapp depends upon Cash CorDapp features cordapp project(':finance:contracts') cordapp project(':finance:workflows') diff --git a/samples/trader-demo/build.gradle b/samples/trader-demo/build.gradle index 68cffdff69..0b5272f7a7 100644 --- a/samples/trader-demo/build.gradle +++ b/samples/trader-demo/build.gradle @@ -32,6 +32,9 @@ configurations { } dependencies { + if (System.getProperty('excludeShell') == null) { + cordaDriver "net.corda:corda-shell:$corda_release_version" + } compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version" cordaCompile project(':client:rpc') diff --git a/testing/test-cli/build.gradle b/testing/test-cli/build.gradle index a668c605f4..d4de7deba0 100644 --- a/testing/test-cli/build.gradle +++ b/testing/test-cli/build.gradle @@ -6,7 +6,7 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version" + compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version" compile "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" compile "junit:junit:${junit_version}" diff --git a/tools/network-builder/build.gradle b/tools/network-builder/build.gradle index 1790147579..51ec4d6339 100644 --- a/tools/network-builder/build.gradle +++ b/tools/network-builder/build.gradle @@ -52,7 +52,7 @@ dependencies { compile "com.typesafe:config:$typesafe_config_version" compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jackson_version" compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version" + compile "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_kotlin_version" compile "info.picocli:picocli:$picocli_version" // TornadoFX: A lightweight Kotlin framework for working with JavaFX UI's.