Skip to content
Matt Magoffin edited this page Jun 29, 2017 · 7 revisions

The SolarSSH server acts as an intermediary between SolarNodes and an administrator, allowing an administrator access to nodes that are not directly accessible over the internet because of network configuration details (such as firewalls). It exposes two main features for a given SolarNode:

  1. a URL for accessing the node web server (and thus, the setup GUI)
  2. a websocket connection to a SSH terminal shell on the node

To provide these features, SolarSSH exposes a RESTful API that a browser can use to control the entire process of authenticating the administrator, getting SolarNode to SSH to SolarSSH, and exposing the features listed above to the browser.

Overview

The general process of using SolarSSH follows these steps:

  1. Create a new SolarSSH session, which contains a unique session ID and other details needed in subsequent steps. A SolarNet security token is required to authenticate the administrator.
  2. Enqueue a StartRemoteSsh instruction with SolarNet, passing in details from the session details returned in step 1. The ID of the instruction is added to the session details for use in subsequent steps.
  3. Using the instruction ID returned in step 2, wait for the instruction to reach the Completed state, which signals that the SolarNode has established the SSH connection with SolarSSH.
  4. At this stage, feature #1 from above is available, and the browser can access the node web server via a URL on the SolarSSH server.
  5. To access the node via SSH, the browser can open a websocket connection to the SolarSSH server and then pass SSH credentials to SolarSSH. SolarSSH will then establish a SSH terminal shell on the node, and connect the shell to the websocket.
  6. At this stage, all text sent over the websocket will be passed to the node's terminal shell, and any text emitted by the shell will be passed back over the websocket to the browser. By using a JavaScript terminal emulator like xterm.js (with that project's attach addon) a full interactive shell can be created right in the browser.

Many of the REST API methods require a SNWSv2 header value be passed on a X-SN-PreSignedAuthorization HTTP header that SolarSSH can use to make requests to specific API methods on SolarNetwork. Passing pre-computed authorization serves a few purposes:

  1. The security token secret is never passed to SolarSSH, so SolarSSH never has any knowledge of it.
  2. SolarSSH can only make the specific requests to SolarNetwork that are explicitly encoded in the pre-computed authorization. As the authorization is unique to each request and includes the details of the request, SolarSSH cannot access anything other than what the authorization allows.
  3. SolarSSH can authenticate the API request when it invokes the HTTP request on SolarNetwork using the pre-computed authorization. If the request is authorized by SolarNetwork, then SolarSSH knows the API request is valid.

The solarnetwork-d3 project has a helper class for computing authorization header values that can be used as an example. SolarSSH issues all requests using HTTPS URLs to the data.solarnetwork.net host.

REST API

All REST responses are encoded as a JSON object, with a minimum of a success boolean property. For example:

{ "success": true }

If there is additional information, it will be provided on a data property, for example:

{ "success": true, "data": { "foo": "bar" } }

If an error occurs, a message and error code will be included, for example:

{ "success": true, "code": 5000, "message": "Bad credentials." }

Create session

This method will create a new SolarSSH session and is the required first step for interacting with SolarSSH. See the webterminal source for an example of invoking this endpoint.

Create session request

GET /api/v1/ssh/session/new
nodeId A query parameter containing the ID of the SolarNode to use the session with.
X-SN-PreSignedAuthorization A HTTP header containing a SNWSv2 authorization header value for making a GET request to the SolarUser view pending instructions API for the given nodeId.
X-SN-Date A HTTP header containing the the date used in the X-SN-PreSignedAuthorization value.

Create session response

The response includes a session object. A typical response looks like this:

{
  "success": true,
  "code": null,
  "message": null,
  "data": {
    "sessionId": "8d0b329c-4845-49df-a7d9-c952fb395a8a",
    "created": 1498590980179,
    "nodeId": 246,
    "host": "ssh.solarnetwork.net",
    "port": 8022,
    "reversePort": 43332,
    "startInstructionId": null,
    "stopInstructionId": null,
    "established": false
  }
}

Session object

A session object contains the following properties:

sessionId A unique ID for the session, as a string. This is also the username the node must use when connecting to SolarSSH.
created The date the session was created, as milliseconds since the epoch.
nodeId The SolarNode ID associated with the session.
host The SSH hostname for the SolarNode to connect to. Typically this will be the same hostname SolarSSH is running on, but it could differ.
port The SSH port for the SolarNode to connect to (on host).
reversePort A reverse listen port for the SolarNode to establish when it connects via SSH, for forwarding to port 22 on localhost, for tunneling SSH traffic back to the node. This would be like the node passing -R 127.0.0.1:reversePort:localhost:22 via OpenSSH. The node is then expected to also request reversePort + 1 for reverse forwarding to port 8080 on localhost, for tunneling HTTP traffic back tothe node. This would be like the node passing -R 127.0.0.1:reversePort+1:localhost:8080 via OpenSSH.
startInstructionId The SolarNetwork instruction ID for the StartRemoteSsh instruction queued for the node. This ID can be used to query on the status of this instruction, and know if the node successfully connected to SolarSSH or not.
stopInstructionId The SolarNetwork instruction ID for the StopRemoteSsh instruction queued for the node. This ID can be used to query on the status of this instruction, and know if the node successfully disconnected to SolarSSH or not.
established A boolean that gets set to true when the node successfully connects and authenticates to SolarSSH.

Start session

This method will enqueue a StartRemoteSsh instruction for the session's node. See the webterminal source for an example of invoking this endpoint.

After this method returns, clients can invoke the View instruction endpoint on SolarNetwork directly to find out if the instruction has been handled correctly by the node. Once the instruction state reaches the Completed state, the SSH connection will be ready for use and the HTTP proxy and websocket shell can be used. See the webterminal source for an example of polling for the Completed instruction state.

Start session request

GET /api/v1/ssh/session/{sessionId}/start
sessionId A path variable containing the ID of the session (originally returned from the Create session endpoint).
X-SN-PreSignedAuthorization A HTTP header containing a SNWSv2 authorization header value for making a POST request to the SolarUser Queue instruction API. The nodeId in the authorized request must be the same node ID value in the session. The topic in the authorized request must be StartRemoteSsh.
X-SN-Date A HTTP header containing the the date used in the X-SN-PreSignedAuthorization value.

For the X-SN-PreSignedAuthorization authorization, the order of the instruction parameters in the authorized request must be:

  1. host - the host from the session
  2. user - the sessionId from the session
  3. port - the port from the session
  4. rport - the reversePort from the session

Start session response

The response includes a session object.

Stop session

This method will enqueue a StopRemoteSsh instruction for the session's node. See the webterminal source for an example of invoking this endpoint. Once this method is invoked, the session is invalidated and subsequent use of the session will fail.

Stop session request

GET /api/v1/ssh/session/{sessionId}/stop
sessionId A path variable containing the ID of the session (originally returned from the Create session endpoint).
X-SN-PreSignedAuthorization A HTTP header containing a SNWSv2 authorization header value for making a POST request to the SolarUser Queue instruction API. The nodeId in the authorized request must be the same node ID value in the session. The topic in the authorized request must be StopRemoteSsh.
X-SN-Date A HTTP header containing the the date used in the X-SN-PreSignedAuthorization value.

For the X-SN-PreSignedAuthorization authorization, the order of the instruction parameters in the authorized request must be:

  1. host - the host from the session
  2. user - the sessionId from the session
  3. port - the port from the session
  4. rport - the reversePort from the session

Stop session response

The response includes a session object.

SolarNode HTTP proxy

Once a session has been started, then SolarSSH will expose a HTTP reverse proxy at /nodeproxy/:sessionId/ that forwards all requests to the node's HTTP server. That URL is publicly available and does not require any authentication itself. However the node HTTP server by default shows the setup GUI, which requires authentication to access. The proxy URL can thus be shared with other administrators freely, and they can administer the node as long as they have credentials to access the node setup GUI.

The HTTP proxy is valid as long as the session is valid. Once the session is stopped the HTTP proxy will be closed.

See the webterminal source for an example of exposing the HTTP proxy to the browser.

Websocket remote shell

Once a session has been started, then SolarSSH will expose a websocket connection at /ssh?sessionId=:sessionId. The session ID must be passed as the sessionId query parameter of the connect URL and a protocol of solarssh. See the webterminal source for an example of opening a remote shell websocket connection.

Once the websocket is connected, then the browser must first send a text message with a JSON payload containing an object with the following properties outlined below. See the webterminal source for an example of authenticating the remote shell websocket connection.

An example JSON payload looks like this:

{
  "cmd": "attach-ssh",
  "data": {
    "authorization": "SNWS2 Credential=0934jLKdjd09d7809djd,SignedHeaders=host;x-sn-date,Signature=910d03505e32dd96a6e1ba60f43a1455335701347249c03c5c93dc495d244ee8",
    "authorization-date": 1498685326942,
    "cols": 100,
    "lines": 24,
    "password": "solar",
    "term": "xterm",
    "username": "solar"
  }
}
cmd The literal string attach-ssh.
data A nested object with authentication details and optional terminal settings.

The data authentication object must contain the following properties:

authorization A string containing a SNWSv2 authorization HTTP header value for making a GET request to the SolarUser Get node metadata endpoint. The nodeId in the authorized request must be the same node ID value in the session.
authorization-date The date used in authorization as a number, as milliseconds since the epoch.
username A string node SSH username to use when attaching the remote shell terminal.
password A string node SSH password to use when attaching the remote shell terminal.

In addition, the following optional properties may be provided:

term A string value to pass as the remote shell terminal type. Defaults to xterm.
cols A number for the number of columns to use for the remote shell terminal. Defaults to 80.
lines The number of lines to use for the remote shell terminal. Defaults to 24.
width A number width in pixels to use for the remote shell terminal. Defaults to 640.
height >A number height in pixels to use for the remote shell terminal. Defaults to 480.
environment An object whose key/value pairs will be passed as environment variables on the remote shell.
Clone this wiki locally