The SSH Plugin

JavaScript

ssh.js - The client-side portion of Gate One's SSH plugin.

GateOne.SSH.autoConnect()

Automatically connects to GateOne.prefs.autoConnectURL if it set.

GateOne.SSH.bookmarkIconHandler(bookmark)

Saves the GateOne.Icons.SSH icon in the given bookmark using GateOne.Bookmarks.storeFavicon().

Note

This gets registered for the 'ssh' and 'telnet' inside of GateOne.SSH.postInit().

GateOne.SSH.commandCompleted(message)

Uses the contents of message to report the results of the command executed via execRemoteCmd().

The message should be something like:

{
    'term': 1,
    'cmd': 'uptime',
    'output': ' 20:45:27 up 13 days,  3:44,  9 users,  load average: 1.21, 0.79, 0.57',
    'result', 'Success'
}

If 'result' is anything other than 'Success' the error will be displayed to the user.

If a callback was registered in GateOne.SSH.remoteCmdCallbacks[term] it will be called like so:

callback(message['output'])

Otherwise the output will just be displayed to the user. After the callback has executed it will be removed from GateOne.SSH.remoteCmdCallbacks.

GateOne.SSH.connect(URL)

Connects to the given SSH URL.

If the current terminal is sitting at the SSH Connect prompt it will be used to make the connection. Otherwise a new terminal will be opened.

GateOne.SSH.createKHPanel()

Creates a panel where the user can edit their known_hosts file and appends it to '#gateone'.

If the panel already exists its contents will be destroyed and re-created.

GateOne.SSH.createPanel()

Creates the SSH identity management panel (the shell of it anyway).

GateOne.SSH.deleteCompleteAction(message)

Called when an identity is deleted, calls GateOne.SSH.loadIDs()

GateOne.SSH.displayHostFingerprint(message)

Displays the host's key as sent by the server via the 'sshjs_display_fingerprint' WebSocket action.

The fingerprint will be colorized using the hex values of the fingerprint as the color code with the last value highlighted in bold.

GateOne.SSH.displayMetadata(identity)

Displays the information about the given identity (its name) in the SSH identities metadata area (on the right). Also displays the buttons that allow the user to delete the identity or upload a certificate.

GateOne.SSH.displayMetadata(container, IDObj, delay)

Creates an SSH identity element using IDObj and places it into container.

delay controls how long it will wait before using a CSS3 effect to move it into view.

GateOne.SSH.duplicateSession(term)

Duplicates the SSH session at term in a new terminal.

GateOne.SSH.enterPassphraseAction(settings)

Displays the dialog/form where a user can enter a passphrase for a given identity (called by the server if something requires it).

GateOne.SSH.execRemoteCmd(term, command, callback, errorback)

Executes command by creating a secondary shell in the background using the multiplexed tunnel of term (works just like duplicateSession()).

Calls callback when the result of command comes back.

Calls errorback if there's an error executing the command.

GateOne.SSH.getConnectString(term)

Asks the SSH plugin on the Gate One server what the SSH connection string is for the given term.

GateOne.SSH.getMaxIDs(elem)

Calculates and returns the number of SSH identities that will fit in the given element ID (elem).

GateOne.SSH.handleConnect(connectString)

Handles the terminal:sshjs_connect WebSocket action which should provide an SSH connectString in the form of 'user@host:port'.

The connectString will be stored in GateOne.Terminal.terminals[term]['sshConnectString'] which is meant to be used in duplicating terminals (because you can't rely on the title).

Also requests the host's public SSH key so it can be displayed to the user.

GateOne.SSH.handleKnownHosts(message)

Updates the sshKHTextArea with the contents of message['known_hosts'].

GateOne.SSH.handleReconnect(message)

Handles the terminal:sshjs_reconnect WebSocket action which should provide an object containing each terminal's SSH connection string. Example message:

{"term": 1, "connect_string": "user@host1:22"}
GateOne.SSH.incomingIDsAction(message)

This gets attached to the 'sshjs_identities_list' WebSocket action. Adds message['identities'] to GateOne.SSH.identities and places them into the Identity Manager.

GateOne.SSH.init()

Creates the SSH Identity Manager panel, adds some buttons to the Info & Tools panel, and registers the following WebSocket actions & events:

GateOne.Net.addAction('terminal:sshjs_connect', GateOne.SSH.handleConnect);
GateOne.Net.addAction('terminal:sshjs_reconnect', GateOne.SSH.handleReconnect);
GateOne.Net.addAction('terminal:sshjs_keygen_complete', GateOne.SSH.keygenComplete);
GateOne.Net.addAction('terminal:sshjs_save_id_complete', GateOne.SSH.saveComplete);
GateOne.Net.addAction('terminal:sshjs_display_fingerprint', GateOne.SSH.displayHostFingerprint);
GateOne.Net.addAction('terminal:sshjs_identities_list', GateOne.SSH.incomingIDsAction);
GateOne.Net.addAction('terminal:sshjs_delete_identity_complete', GateOne.SSH.deleteCompleteAction);
GateOne.Net.addAction('terminal:sshjs_cmd_output', GateOne.SSH.commandCompleted);
GateOne.Net.addAction('terminal:sshjs_ask_passphrase', GateOne.SSH.enterPassphraseAction);
GateOne.Net.addAction('terminal:sshjs_known_hosts', GateOne.SSH.handleKnownHosts);
GateOne.Events.on("terminal:new_terminal", GateOne.SSH.getConnectString);
GateOne.SSH.keygenComplete(message)

Called when we receive a message from the server indicating a keypair was generated successfully.

GateOne.SSH.loadIDs()

Toggles the SSH Identity Manager into view (if not already visible) and asks the server to send us our list of identities.

GateOne.SSH.newIDForm()

Displays the dialog/form where the user can create or edit an SSH identity.

GateOne.SSH.postInit()

Registers our 'ssh' and 'telnet' protocol handlers with the Bookmarks plugin.

Note

These things are run inside of the postInit() function in order to ensure that GateOne.Bookmarks is loaded (and ready-to-go) first.

GateOne.SSH.saveComplete(message)

Called when we receive a message from the server indicating the uploaded identity was saved.

GateOne.SSH.uploadCertificateForm(identity)

Displays the dialog/form where a user can add or replace a certificate associated with their identity.

identity should be the name of the identity associated with this certificate.

GateOne.SSH.uploadIDForm()

Displays the dialog/form where a user can upload an SSH identity (that's already been created).

Python

ssh.py - A plugin for Gate One that adds additional SSH-specific features.

Hooks

This Python plugin file implements the following hooks:

hooks = {
    'WebSocket': {
        'terminal:ssh_get_known_hosts': get_known_hosts,
        'terminal:ssh_save_known_hosts': save_known_hosts,
        'terminal:ssh_get_connect_string': get_connect_string,
        'terminal:ssh_execute_command': ws_exec_command,
        'terminal:ssh_get_identities': get_identities,
        'terminal:ssh_get_public_key': get_public_key,
        'terminal:ssh_get_private_key': get_private_key,
        'terminal:ssh_get_host_fingerprint': get_host_fingerprint,
        'terminal:ssh_gen_new_keypair': generate_new_keypair,
        'terminal:ssh_store_id_file': store_id_file,
        'terminal:ssh_delete_identity': delete_identity,
        'terminal:ssh_set_default_identities': set_default_identities
    },
    'Escape': opt_esc_handler,
    'Events': {
        'terminal:authenticate': send_css_template,
        'terminal:authenticate': create_user_ssh_dir
    }
}

Docstrings

exception ssh.SSHMultiplexingException[source]

Called when there's a failure trying to open a sub-shell via OpenSSH's Master mode multiplexing capability.

exception ssh.SSHExecutionException[source]

Called when there's an error trying to execute a command in the slave.

exception ssh.SSHKeygenException[source]

Called when there's an error trying to generate a public/private keypair.

exception ssh.SSHKeypairException[source]

Called when there's an error trying to save public/private keypair or certificate.

exception ssh.SSHPassphraseException[source]

Called when we try to generate/decode something that requires a passphrase but no passphrase was given.

ssh.get_ssh_dir(self)[source]

Given a gateone.TerminalWebSocket (self) instance, return the current user's ssh directory

Note

If the user's ssh directory doesn't start with a . (dot) it will be renamed.

ssh.open_sub_channel(self, term)[source]

Opens a sub-channel of communication by executing a new shell on the SSH server using OpenSSH's Master mode capability (it spawns a new slave) and returns the resulting termio.Multiplex instance. If a slave has already been opened for this purpose it will re-use the existing channel.

ssh.wait_for_prompt(term, cmd, errorback, callback, m_instance, matched)[source]

Called by termio.Multiplex.expect() inside of execute_command(), clears the screen and executes cmd. Also, sets an expect() to call get_cmd_output() when the end of the command output is detected.

ssh.get_cmd_output(term, errorback, callback, m_instance, matched)[source]

Captures the output of the command executed inside of wait_for_prompt() and calls callback if it isn't None.

ssh.terminate_sub_channel(m_instance)[source]

Calls m_instance.terminate() and deletes it from OPEN_SUBCHANNELS.

ssh.timeout_sub_channel(m_instance)[source]

Called when the sub-channel times out by way of an termio.Multiplex.expect pattern that should never match anything.

ssh.got_error(self, m_instance, match=None, term=None, cmd=None)[source]

Called if execute_command() encounters a problem/timeout.

match is here in case we want to use it for a positive match of an error.

ssh.execute_command(self, term, cmd, callback=None)[source]

Execute the given command (cmd) on the given term using the existing SSH tunnel (taking advantage of Master mode) and call callback with the output of said command and the current termio.Multiplex instance as arguments like so:

callback(output, m_instance)

If callback is not provided then the command will be executed and any output will be ignored.

Note

This will not result in a new terminal being opened on the client--it simply executes a command and returns the result using the existing SSH tunnel.

ssh.send_result(self, term, cmd, output, m_instance)[source]

Called by ws_exec_command() when the output of the executed command has been captured successfully. Writes a message to the client with the command's output and some relevant metadata.

ssh.ws_exec_command(self, settings)[source]

Takes the necessary variables from settings and calls execute_command().

settings should be a dict that contains a 'term' and a 'cmd' to execute.

Tip

This function can be used to quickly execute a command and return its result from the client over an existing SSH connection without requiring the user to enter their password! See execRemoteCmd() in ssh.js.

ssh.get_known_hosts(self)[source]

Attached to the (server-side) terminal:ssh_get_known_hosts WebSocket action; returns the current user's known_hosts file.

ssh.save_known_hosts(self, known_hosts)[source]

Attached to the (server-side) terminal:ssh_save_known_hosts WebSocket action; saves the given known_hosts (string) to the user's known_hosts file.

ssh.get_connect_string(self, term)[source]

Attached to the (server-side) terminal:ssh_get_connect_string WebSocket action; writes the connection string associated with term to the WebSocket like so:

{'terminal:sshjs_reconnect': {*term*: <connection string>}}

In ssh.js we attach a WebSocket action to 'terminal:sshjs_reconnect' that assigns the connection string sent by this function to GateOne.Terminal.terminals[*term*]['sshConnectString'].

ssh.get_key(self, name, public)[source]

Returns the private SSH key associated with name to the client. If public is True, returns the public key to the client.

ssh.get_public_key(self, name)[source]

Returns the user's public key file named name.

ssh.get_private_key(self, name)[source]

Returns the user's private key file named name.

ssh.get_host_fingerprint(self, settings)[source]

Returns a the hash of the given host's public key by making a remote connection to the server (not just by looking at known_hosts).

ssh.generate_new_keypair(self, settings)[source]

Calls openssh_generate_new_keypair() or dropbear_generate_new_keypair() depending on what's available on the system.

ssh.overwrite(m_instance, match)[source]

Called if we get asked to overwrite an existing keypair.

ssh.openssh_generate_new_keypair(self, name, path, keytype=None, passphrase='', bits=None, comment='')[source]

Generates a new private and public key pair--stored in the user's directory using the given name and other optional parameters (using OpenSSH).

If keytype is given, it must be one of "ecdsa", "rsa" or "dsa" (case insensitive). If keytype is "rsa" or "ecdsa", bits may be specified to specify the size of the key.

Note

Defaults to generating a 521-byte ecdsa key if OpenSSH is version 5.7+. Otherwise a 2048-bit rsa key will be used.

ssh.dropbear_generate_new_keypair(self, name, path, keytype=None, passphrase='', bits=None, comment='')[source]

Note

Not implemented yet

ssh.openssh_generate_public_key(self, path, passphrase=None, settings=None)[source]

Generates a public key from the given private key at path. If a passphrase is provided, it will be used to generate the public key (if necessary).

ssh.store_id_file(self, settings)[source]

Stores the given settings['private'] and/or settings['public'] keypair in the user's ssh directory as settings['name'] and/or settings['name'].pub, respectively. Either file can be saved independent of each other (in case this function needs to be called multiple times to save each respective file).

Also, a settings['certificate'] may be provided to be saved along with the private and public keys. It will be saved as settings['name']-cert.pub.

Note

I've found the following website helpful in understanding how to use OpenSSH with SSL certificates: http://blog.habets.pp.se/2011/07/OpenSSH-certificates

Tip

Using signed-by-a-CA certificates is very handy because allows you to revoke the user's SSH key(s). e.g. If they left the company.

ssh.delete_identity(self, name)[source]

Removes the identity associated with name. For example if name is 'testkey', 'testkey' and 'testkey.pub' would be removed from the user's ssh directory (and 'testkey-cert.pub' if present).

ssh.get_identities(self, *anything)[source]

Sends a message to the client with a list of the identities stored on the server for the current user.

anything is just there because the client needs to send something along with the 'action'.

ssh.set_default_identities(self, identities)[source]

Given a list of identities, mark them as defaults to use in all outbound SSH connections by writing them to <user's ssh dir>/.default_ids. If identities is empty, no identities will be used in outbound connections.

Note

Whenever this function is called it will overwrite whatever is in default_ids.

ssh.set_ssh_socket(self, term, path)[source]

Given a term and path, sets self.loc_terms[term]['ssh_socket'] = path.

ssh.set_ssh_connect_string(self, term, connect_string)[source]

Given a term and connect_string, sets self.loc_terms[term]['ssh_connect_string'] = connect_string.

ssh.opt_esc_handler(self, text, term=None, multiplex=None)[source]

Handles text passed from the special optional escape sequance handler. We use it to tell ssh.js what the SSH connection string is so it can use that information to duplicate sessions (if the user so desires). For reference, the specific string which will call this function from a terminal app is:

\x1b]_;ssh|<whatever>\x07

See also

gateone.TerminalWebSocket.esc_opt_handler and terminal.Terminal._opt_handler()

ssh.create_user_ssh_dir(self)[source]

To be called by the 'Auth' hook that gets called after the user is done authenticating, ensures that the <user's dir>/ssh directory exists.

ssh.send_ssh_css_template(self)[source]

Sends our ssh.css template to the client using the 'load_style' WebSocket action. The rendered template will be saved in Gate One's 'cache_dir'.

ssh.initialize(self)[source]

Called inside of TerminalApplication.initialize() shortly after the WebSocket is instantiated. Attaches our two terminal:authenticate events (to create the user's .ssh dir and send our CSS template) and ensures that the ssh_connect.py script is executable.