All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ammonite.sshd.SshServer.scala Maven / Gradle / Ivy

package ammonite.sshd

import java.util.Collections

import org.apache.sshd.agent.SshAgentFactory
import org.apache.sshd.common._
import org.apache.sshd.common.file.FileSystemFactory
import org.apache.sshd.common.session.{ConnectionService, Session}
import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider
import org.apache.sshd.server.{Command, CommandFactory, SshServer => SshServerImpl}

/**
 * A factory to simplify creation of ssh server
 */
object SshServer {
  def apply(options: SshServerConfig, shellServer: ShellSession.Server) = {
    val sshServer = SshServerImpl.setUpDefaultServer()
    sshServer.setHost(options.address)
    sshServer.setPort(options.port)
    options.passwordAuthenticator.foreach { auth =>
      sshServer.setPasswordAuthenticator(auth)
      sshServer.setKeyboardInteractiveAuthenticator(
        new DefaultKeyboardInteractiveAuthenticator()
      )
    }
    options.publicKeyAuthenticator.foreach { auth =>
      sshServer.setPublickeyAuthenticator(auth)
    }
    sshServer.setKeyPairProvider(keyPairProvider(options))
    sshServer.setShellFactory(new Factory[Command] {
      override def create(): Command = new ShellSession(shellServer)
    })
    disableUnsupportedChannels(sshServer)
  }

  def keyPairProvider(options: SshServerConfig) = {
    val hostKeyFile = touch(
      options.hostKeyFile.getOrElse(fallbackHostkeyFilePath(options))
    )
    val provider = new SimpleGeneratorHostKeyProvider(hostKeyFile.wrapped)
    provider.setAlgorithm("RSA")
    provider
  }

  private def disableUnsupportedChannels(sshServer: SshServerImpl) = {
    // exec can't really be disabled
    // but it can report error on trying to run any command it received
    sshServer.setCommandFactory(new CommandFactory {
      override def createCommand(command: String): Command =
        throw new IllegalArgumentException("exec is not supported")
    })
    sshServer.setSubsystemFactories(Collections.emptyList())
    sshServer.setTcpipForwardingFilter(null)
    sshServer.setAgentFactory(new SshAgentFactory {
      override def createServer(service: ConnectionService) = null
      override def createClient(manager: FactoryManager) = null
      override def getChannelForwardingFactory = null
    })
    sshServer.setFileSystemFactory(new FileSystemFactory {
      override def createFileSystem(session: Session) = null
    })
    sshServer
  }

  // this is a user-safe options.
  // Server should have stable key
  // to not violate the user under threat of MITM attack
  private def fallbackHostkeyFilePath(options:SshServerConfig) =
    options.ammoniteHome/'cache/'ssh/'hostkeys

  def touch(file: os.Path): os.Path = {
    if (!os.exists(file)) {
      os.write(file, Array.empty[Byte], createFolders = true)
    }
    file
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy