CORDA-3520, CORDA-3550: SSH memory leak and security (#5873)

* CORDA-3520: Closing RPC connection on SSH disconnect
CORDA-3550: Remove support for outdated ciphers and algorithms from SSH

* CORDA-3550: Remove support for outdated ciphers and algorithms from SSH
This commit is contained in:
Denis Rekalov 2020-01-22 14:40:25 +00:00 committed by Matthew Nesbit
parent 597658c4ab
commit 6a2249e697
6 changed files with 30 additions and 9 deletions

View File

@ -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')

View File

@ -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 <corda_configuration_file_overriding_config>` 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

View File

@ -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<String>>(), AuthenticationPlugin<String> {
class CordaAuthenticationPlugin(private val makeRPCConnection: (username: String, credential: String) -> CordaRPCConnection) : CRaSHPlugin<AuthenticationPlugin<String>>(), AuthenticationPlugin<String> {
companion object {
private val logger = loggerFor<CordaAuthenticationPlugin>()
@ -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) {

View File

@ -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>(), DisconnectPlugin {
override fun getImplementation() = this
override fun onDisconnect(userName: String?, authInfo: AuthInfo?) {
(authInfo as? CordaSSHAuthInfo)?.rpcConn?.forceClose()
}
}

View File

@ -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 {

View File

@ -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<String, Any>()
@ -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)