diff --git a/build.gradle b/build.gradle index 291e458141..bdb66ed4ec 100644 --- a/build.gradle +++ b/build.gradle @@ -104,7 +104,7 @@ buildscript { ext.dependency_checker_version = '5.2.0' ext.commons_collections_version = '4.3' ext.beanutils_version = '1.9.3' - ext.crash_version = '1.7.1' + ext.crash_version = '1.7.2' ext.jsr305_version = constants.getProperty("jsr305Version") ext.shiro_version = '1.4.1' ext.artifactory_plugin_version = constants.getProperty('artifactoryPluginVersion') diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 8d879ea2d1..96d3a30575 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -103,6 +103,8 @@ Unreleased * Environment variables and system properties can now be provided with underscore separators instead of dots. Neither are case sensitive. See :ref:`overriding config values ` for more information. +* SSH server in the :doc:`shell` has been updated to remove outdated weak ciphers and algorithms. + .. _changelog_v4.1: Version 4.1 diff --git a/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaAuthenticationPlugin.kt b/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaAuthenticationPlugin.kt index b7c56ab070..9ed0b743c8 100644 --- a/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaAuthenticationPlugin.kt +++ b/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaAuthenticationPlugin.kt @@ -1,5 +1,6 @@ package net.corda.tools.shell +import net.corda.client.rpc.CordaRPCConnection import net.corda.core.internal.messaging.InternalCordaRPCOps import net.corda.core.utilities.loggerFor import org.apache.activemq.artemis.api.core.ActiveMQSecurityException @@ -7,7 +8,7 @@ import org.crsh.auth.AuthInfo import org.crsh.auth.AuthenticationPlugin import org.crsh.plugin.CRaSHPlugin -class CordaAuthenticationPlugin(private val rpcOps: (username: String, credential: String) -> InternalCordaRPCOps) : CRaSHPlugin>(), AuthenticationPlugin { +class CordaAuthenticationPlugin(private val makeRPCConnection: (username: String, credential: String) -> CordaRPCConnection) : CRaSHPlugin>(), AuthenticationPlugin { companion object { private val logger = loggerFor() @@ -23,8 +24,9 @@ class CordaAuthenticationPlugin(private val rpcOps: (username: String, credentia return AuthInfo.UNSUCCESSFUL } try { - val ops = rpcOps(username, credential) - return CordaSSHAuthInfo(true, ops, isSsh = true) + val connection = makeRPCConnection(username, credential) + val ops = connection.proxy as InternalCordaRPCOps + return CordaSSHAuthInfo(true, ops, isSsh = true, rpcConn = connection) } catch (e: ActiveMQSecurityException) { logger.warn(e.message) } catch (e: Exception) { diff --git a/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaDisconnectPlugin.kt b/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaDisconnectPlugin.kt new file mode 100644 index 0000000000..ba33dbbc8c --- /dev/null +++ b/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaDisconnectPlugin.kt @@ -0,0 +1,13 @@ +package net.corda.tools.shell + +import org.crsh.auth.AuthInfo +import org.crsh.auth.DisconnectPlugin +import org.crsh.plugin.CRaSHPlugin + +class CordaDisconnectPlugin : CRaSHPlugin(), DisconnectPlugin { + override fun getImplementation() = this + + override fun onDisconnect(userName: String?, authInfo: AuthInfo?) { + (authInfo as? CordaSSHAuthInfo)?.rpcConn?.forceClose() + } +} diff --git a/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaSSHAuthInfo.kt b/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaSSHAuthInfo.kt index 787a73aaa9..33fdae2fb9 100644 --- a/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaSSHAuthInfo.kt +++ b/tools/shell/src/main/kotlin/net/corda/tools/shell/CordaSSHAuthInfo.kt @@ -1,12 +1,14 @@ package net.corda.tools.shell import com.fasterxml.jackson.databind.ObjectMapper +import net.corda.client.rpc.CordaRPCConnection import net.corda.core.internal.messaging.InternalCordaRPCOps import net.corda.tools.shell.InteractiveShell.createYamlInputMapper import net.corda.tools.shell.utlities.ANSIProgressRenderer import org.crsh.auth.AuthInfo -class CordaSSHAuthInfo(val successful: Boolean, val rpcOps: InternalCordaRPCOps, val ansiProgressRenderer: ANSIProgressRenderer? = null, val isSsh: Boolean = false) : AuthInfo { +class CordaSSHAuthInfo(val successful: Boolean, val rpcOps: InternalCordaRPCOps, val ansiProgressRenderer: ANSIProgressRenderer? = null, + val isSsh: Boolean = false, val rpcConn: CordaRPCConnection? = null) : AuthInfo { override fun isSuccessful(): Boolean = successful val yamlInputMapper: ObjectMapper by lazy { diff --git a/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt b/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt index c4e33df84a..58b9692b0d 100644 --- a/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt +++ b/tools/shell/src/main/kotlin/net/corda/tools/shell/InteractiveShell.kt @@ -94,7 +94,7 @@ const val STANDALONE_SHELL_PERMISSION = "ALL" @Suppress("MaxLineLength") object InteractiveShell { private val log = LoggerFactory.getLogger(javaClass) - private lateinit var rpcOps: (username: String, password: String) -> InternalCordaRPCOps + private lateinit var makeRPCConnection: (username: String, password: String) -> CordaRPCConnection private lateinit var ops: InternalCordaRPCOps private lateinit var rpcConn: CordaRPCConnection private var shell: Shell? = null @@ -112,7 +112,7 @@ object InteractiveShell { } fun startShell(configuration: ShellConfiguration, classLoader: ClassLoader? = null, standalone: Boolean = false) { - rpcOps = { username: String, password: String -> + makeRPCConnection = { username: String, password: String -> val connection = if (standalone) { CordaRPCClient( configuration.hostAndPort, @@ -130,7 +130,7 @@ object InteractiveShell { ).start(username, password) } rpcConn = connection - connection.proxy as InternalCordaRPCOps + connection } launchShell(configuration, standalone, classLoader) } @@ -252,7 +252,8 @@ object InteractiveShell { // Don't use the Java language plugin (we may not have tools.jar available at runtime), this // will cause any commands using JIT Java compilation to be suppressed. In CRaSH upstream that // is only the 'jmx' command. - return super.getPlugins().filterNot { it is JavaLanguage } + CordaAuthenticationPlugin(rpcOps) + return super.getPlugins().filterNot { it is JavaLanguage } + CordaAuthenticationPlugin(makeRPCConnection) + + CordaDisconnectPlugin() } } val attributes = emptyMap() @@ -260,6 +261,7 @@ object InteractiveShell { context.refresh() this.config = config start(context) + val rpcOps = { username: String, password: String -> makeRPCConnection(username, password).proxy as InternalCordaRPCOps } ops = makeRPCOps(rpcOps, localUserName, localUserPassword) return context.getPlugin(ShellFactory::class.java).create(null, CordaSSHAuthInfo(false, ops, StdoutANSIProgressRenderer), shellSafety)