feat(auth): ssh private key auth implemented via config.json (#161)

If config.json is present and user.privatekey has an ssh-rsa private key defined as well as a user.name, the SSH server will staticlly authenticate to whatever host is specified on the URL with those credentials.

The ssh-rsa private key must have is line returns replaced with the litaral \n

Example: "-----BEGIN RSA PRIVATE KEY-----\nblahblahblah\n"
This commit is contained in:
Bill Church 2019-11-15 17:22:53 -05:00 committed by GitHub
parent 65d6ec6845
commit 342df8eb9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 18 additions and 9 deletions

View file

@ -6,10 +6,13 @@
"user": { "user": {
"name": null, "name": null,
"password": null "password": null
"privatekey": null,
}, },
"ssh": { "ssh": {
"host": null, "host": null,
"port": 22, "port": 22,
"localAddress": null,
"localPort": null,
"term": "xterm-color", "term": "xterm-color",
"readyTimeout": 20000, "readyTimeout": 20000,
"keepaliveInterval": 120000, "keepaliveInterval": 120000,

View file

@ -19,7 +19,8 @@ let config = {
}, },
user: { user: {
name: null, name: null,
password: null password: null,
privatekey: null
}, },
ssh: { ssh: {
host: null, host: null,
@ -111,7 +112,7 @@ var app = express()
var compression = require('compression') var compression = require('compression')
var server = require('http').Server(app) var server = require('http').Server(app)
var myutil = require('./util') var myutil = require('./util')
myutil.setDefaultCredentials(config.user.name, config.user.password); myutil.setDefaultCredentials(config.user.name, config.user.password, config.user.privatekey);
var validator = require('validator') var validator = require('validator')
var io = require('socket.io')(server, { serveClient: false }) var io = require('socket.io')(server, { serveClient: false })
var socket = require('./socket') var socket = require('./socket')
@ -132,6 +133,7 @@ app.get('/reauth', function (req, res, next) {
res.status(401).send('<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=' + r + '"></head><body bgcolor="#000"></body></html>') res.status(401).send('<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=' + r + '"></head><body bgcolor="#000"></body></html>')
}) })
// eslint-disable-next-line complexity
app.get('/ssh/host/:host?', function (req, res, next) { app.get('/ssh/host/:host?', function (req, res, next) {
res.sendFile(path.join(path.join(publicPath, 'client.htm'))) res.sendFile(path.join(path.join(publicPath, 'client.htm')))
// capture, assign, and validated variables // capture, assign, and validated variables

View file

@ -114,7 +114,7 @@ module.exports = function socket (socket) {
debugWebSSH2('conn.on(\'keyboard-interactive\')') debugWebSSH2('conn.on(\'keyboard-interactive\')')
finish([socket.request.session.userpassword]) finish([socket.request.session.userpassword])
}) })
if (socket.request.session.username && socket.request.session.userpassword && socket.request.session.ssh) { if (socket.request.session.username && (socket.request.session.userpassword || socket.request.session.privatekey) && socket.request.session.ssh) {
// console.log('hostkeys: ' + hostkeys[0].[0]) // console.log('hostkeys: ' + hostkeys[0].[0])
conn.connect({ conn.connect({
host: socket.request.session.ssh.host, host: socket.request.session.ssh.host,
@ -123,6 +123,7 @@ module.exports = function socket (socket) {
localPort: socket.request.session.ssh.localPort, localPort: socket.request.session.ssh.localPort,
username: socket.request.session.username, username: socket.request.session.username,
password: socket.request.session.userpassword, password: socket.request.session.userpassword,
privateKey: socket.request.session.privatekey,
tryKeyboard: true, tryKeyboard: true,
algorithms: socket.request.session.ssh.algorithms, algorithms: socket.request.session.ssh.algorithms,
readyTimeout: socket.request.session.ssh.readyTimeout, readyTimeout: socket.request.session.ssh.readyTimeout,
@ -143,6 +144,7 @@ module.exports = function socket (socket) {
* @param {string} myFunc Function calling this function * @param {string} myFunc Function calling this function
* @param {object} err error object or error message * @param {object} err error object or error message
*/ */
// eslint-disable-next-line complexity
function SSHerror (myFunc, err) { function SSHerror (myFunc, err) {
var theError var theError
if (socket.request.session) { if (socket.request.session) {

View file

@ -7,11 +7,12 @@ require('colors') // allow for color property extensions in log messages
var debug = require('debug')('WebSSH2') var debug = require('debug')('WebSSH2')
var Auth = require('basic-auth') var Auth = require('basic-auth')
let defaultCredentials = {username: null, password: null}; let defaultCredentials = {username: null, password: null, privatekey: null};
exports.setDefaultCredentials = function (username, password) { exports.setDefaultCredentials = function (username, password, privatekey) {
defaultCredentials.username = username; defaultCredentials.username = username
defaultCredentials.password = password; defaultCredentials.password = password
defaultCredentials.privatekey = privatekey
} }
exports.basicAuth = function basicAuth (req, res, next) { exports.basicAuth = function basicAuth (req, res, next) {
@ -25,8 +26,9 @@ exports.basicAuth = function basicAuth (req, res, next) {
} else { } else {
req.session.username = defaultCredentials.username; req.session.username = defaultCredentials.username;
req.session.userpassword = defaultCredentials.password; req.session.userpassword = defaultCredentials.password;
req.session.privatekey = defaultCredentials.privatekey;
} }
if (!req.session.userpassword) { if ( (!req.session.userpassword) && (!req.session.privatekey) ) {
res.statusCode = 401 res.statusCode = 401
debug('basicAuth credential request (401)') debug('basicAuth credential request (401)')
res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"') res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"')