From 342df8eb9cafba52eb63b50a60e11e1431d6fbd4 Mon Sep 17 00:00:00 2001 From: Bill Church Date: Fri, 15 Nov 2019 17:22:53 -0500 Subject: [PATCH] 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" --- app/config.json.sample | 3 +++ app/server/app.js | 6 ++++-- app/server/socket.js | 6 ++++-- app/server/util.js | 12 +++++++----- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/config.json.sample b/app/config.json.sample index d069d0c..fe7adb2 100644 --- a/app/config.json.sample +++ b/app/config.json.sample @@ -6,10 +6,13 @@ "user": { "name": null, "password": null + "privatekey": null, }, "ssh": { "host": null, "port": 22, + "localAddress": null, + "localPort": null, "term": "xterm-color", "readyTimeout": 20000, "keepaliveInterval": 120000, diff --git a/app/server/app.js b/app/server/app.js index 7d80db8..d2ea822 100644 --- a/app/server/app.js +++ b/app/server/app.js @@ -19,7 +19,8 @@ let config = { }, user: { name: null, - password: null + password: null, + privatekey: null }, ssh: { host: null, @@ -111,7 +112,7 @@ var app = express() var compression = require('compression') var server = require('http').Server(app) 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 io = require('socket.io')(server, { serveClient: false }) var socket = require('./socket') @@ -132,6 +133,7 @@ app.get('/reauth', function (req, res, next) { res.status(401).send('') }) +// eslint-disable-next-line complexity app.get('/ssh/host/:host?', function (req, res, next) { res.sendFile(path.join(path.join(publicPath, 'client.htm'))) // capture, assign, and validated variables diff --git a/app/server/socket.js b/app/server/socket.js index b528978..156f9e2 100644 --- a/app/server/socket.js +++ b/app/server/socket.js @@ -108,13 +108,13 @@ module.exports = function socket (socket) { }) conn.on('end', function connOnEnd (err) { SSHerror('CONN END BY HOST', err) }) - conn.on('close', function connOnClose (err) { SSHerror('CONN CLOSE', err) }) + conn.on('close', function connOnClose (err) { SSHerror('CONN CLOSE', err) }) conn.on('error', function connOnError (err) { SSHerror('CONN ERROR', err) }) conn.on('keyboard-interactive', function connOnKeyboardInteractive (name, instructions, instructionsLang, prompts, finish) { debugWebSSH2('conn.on(\'keyboard-interactive\')') 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]) conn.connect({ host: socket.request.session.ssh.host, @@ -123,6 +123,7 @@ module.exports = function socket (socket) { localPort: socket.request.session.ssh.localPort, username: socket.request.session.username, password: socket.request.session.userpassword, + privateKey: socket.request.session.privatekey, tryKeyboard: true, algorithms: socket.request.session.ssh.algorithms, readyTimeout: socket.request.session.ssh.readyTimeout, @@ -143,6 +144,7 @@ module.exports = function socket (socket) { * @param {string} myFunc Function calling this function * @param {object} err error object or error message */ + // eslint-disable-next-line complexity function SSHerror (myFunc, err) { var theError if (socket.request.session) { diff --git a/app/server/util.js b/app/server/util.js index 14d3e63..0ca3dca 100644 --- a/app/server/util.js +++ b/app/server/util.js @@ -7,11 +7,12 @@ require('colors') // allow for color property extensions in log messages var debug = require('debug')('WebSSH2') var Auth = require('basic-auth') -let defaultCredentials = {username: null, password: null}; +let defaultCredentials = {username: null, password: null, privatekey: null}; -exports.setDefaultCredentials = function (username, password) { - defaultCredentials.username = username; - defaultCredentials.password = password; +exports.setDefaultCredentials = function (username, password, privatekey) { + defaultCredentials.username = username + defaultCredentials.password = password + defaultCredentials.privatekey = privatekey } exports.basicAuth = function basicAuth (req, res, next) { @@ -25,8 +26,9 @@ exports.basicAuth = function basicAuth (req, res, next) { } else { req.session.username = defaultCredentials.username; req.session.userpassword = defaultCredentials.password; + req.session.privatekey = defaultCredentials.privatekey; } - if (!req.session.userpassword) { + if ( (!req.session.userpassword) && (!req.session.privatekey) ) { res.statusCode = 401 debug('basicAuth credential request (401)') res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"')