From f1e5d4a13ce890439bc154c3212335869336adb4 Mon Sep 17 00:00:00 2001 From: Nils Lundquist Date: Mon, 13 Jan 2020 12:47:24 -0700 Subject: [PATCH] Allow websocket server to take ssh host as query parameter. This allows sockets to be opened without loading the client page first to set up the session. This simplifies use when using WebSSH2 with an alternative client. Cleaned up the derivation of configuration from defaults, static config file, request params & session --- app/server/app.js | 150 ++------------------ app/server/socket.js | 321 ++++++++++++++++++++++++++++++------------- app/server/util.js | 23 ++-- 3 files changed, 248 insertions(+), 246 deletions(-) diff --git a/app/server/app.js b/app/server/app.js index 5f0b490..f29ad33 100644 --- a/app/server/app.js +++ b/app/server/app.js @@ -3,105 +3,18 @@ // app.js var path = require('path') -var fs = require('fs') var nodeRoot = path.dirname(require.main.filename) -var configPath = path.join(nodeRoot, 'config.json') var publicPath = path.join(nodeRoot, 'client', 'public') -console.log('WebSSH2 service reading config from: ' + configPath) +var config = require('./config') var express = require('express') var logger = require('morgan') - -// sane defaults if config.json or parts are missing -let config = { - listen: { - ip: '0.0.0.0', - port: 2222 - }, - user: { - name: null, - password: null, - privatekey: null - }, - ssh: { - host: null, - port: 22, - term: 'xterm-color', - readyTimeout: 20000, - keepaliveInterval: 120000, - keepaliveCountMax: 10, - allowedSubnets: [] - }, - terminal: { - cursorBlink: true, - scrollback: 10000, - tabStopWidth: 8, - bellStyle: 'sound' - }, - header: { - text: null, - background: 'green' - }, - session: { - name: 'WebSSH2', - secret: 'mysecret' - }, - options: { - challengeButton: true, - allowreauth: true - }, - algorithms: { - kex: [ - 'ecdh-sha2-nistp256', - 'ecdh-sha2-nistp384', - 'ecdh-sha2-nistp521', - 'diffie-hellman-group-exchange-sha256', - 'diffie-hellman-group14-sha1' - ], - cipher: [ - 'aes128-ctr', - 'aes192-ctr', - 'aes256-ctr', - 'aes128-gcm', - 'aes128-gcm@openssh.com', - 'aes256-gcm', - 'aes256-gcm@openssh.com', - 'aes256-cbc' - ], - hmac: [ - 'hmac-sha2-256', - 'hmac-sha2-512', - 'hmac-sha1' - ], - compress: [ - 'none', - 'zlib@openssh.com', - 'zlib' - ] - }, - serverlog: { - client: false, - server: false - }, - accesslog: false, - verify: false -} - -// test if config.json exists, if not provide error message but try to run -// anyway -try { - if (fs.existsSync(configPath)) { - console.log('ephemeral_auth service reading config from: ' + configPath) - config = require('read-config')(configPath) - } else { - console.error('\n\nERROR: Missing config.json for webssh. Current config: ' + JSON.stringify(config)) - console.error('\n See config.json.sample for details\n\n') - } -} catch (err) { - console.error('\n\nERROR: Missing config.json for webssh. Current config: ' + JSON.stringify(config)) - console.error('\n See config.json.sample for details\n\n') - console.error('ERROR:\n\n ' + err) -} - +var app = express() +var compression = require('compression') +var server = require('http').Server(app) +var myutil = require('./util') +var io = require('socket.io')(server, { serveClient: false }) +var socket = require('./socket') +var expressOptions = require('./expressOptions') var session = require('express-session')({ secret: config.session.secret, name: config.session.name, @@ -109,15 +22,6 @@ var session = require('express-session')({ saveUninitialized: false, unset: 'destroy' }) -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, config.user.privatekey); -var validator = require('validator') -var io = require('socket.io')(server, { serveClient: false }) -var socket = require('./socket') -var expressOptions = require('./expressOptions') // express app.use(compression({ level: 9 })) @@ -137,44 +41,6 @@ app.get('/reauth', function (req, res, next) { // 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 - req.session.ssh = { - host: (validator.isIP(req.params.host + '') && req.params.host) || - (validator.isFQDN(req.params.host) && req.params.host) || - (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.params.host) && - req.params.host) || config.ssh.host, - port: (validator.isInt(req.query.port + '', { min: 1, max: 65535 }) && - req.query.port) || config.ssh.port, - localAddress: config.ssh.localAddress, - localPort: config.ssh.localPort, - header: { - name: req.query.header || config.header.text, - background: req.query.headerBackground || config.header.background - }, - algorithms: config.algorithms, - keepaliveInterval: config.ssh.keepaliveInterval, - keepaliveCountMax: config.ssh.keepaliveCountMax, - allowedSubnets: config.ssh.allowedSubnets, - term: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) && - req.query.sshterm) || config.ssh.term, - terminal: { - cursorBlink: (validator.isBoolean(req.query.cursorBlink + '') ? myutil.parseBool(req.query.cursorBlink) : config.terminal.cursorBlink), - scrollback: (validator.isInt(req.query.scrollback + '', { min: 1, max: 200000 }) && req.query.scrollback) ? req.query.scrollback : config.terminal.scrollback, - tabStopWidth: (validator.isInt(req.query.tabStopWidth + '', { min: 1, max: 100 }) && req.query.tabStopWidth) ? req.query.tabStopWidth : config.terminal.tabStopWidth, - bellStyle: ((req.query.bellStyle) && (['sound', 'none'].indexOf(req.query.bellStyle) > -1)) ? req.query.bellStyle : config.terminal.bellStyle - }, - allowreplay: config.options.challengeButton || (validator.isBoolean(req.headers.allowreplay + '') ? myutil.parseBool(req.headers.allowreplay) : false), - allowreauth: config.options.allowreauth || false, - mrhsession: ((validator.isAlphanumeric(req.headers.mrhsession + '') && req.headers.mrhsession) ? req.headers.mrhsession : 'none'), - serverlog: { - client: config.serverlog.client || false, - server: config.serverlog.server || false - }, - readyTimeout: (validator.isInt(req.query.readyTimeout + '', { min: 1, max: 300000 }) && - req.query.readyTimeout) || config.ssh.readyTimeout - } - if (req.session.ssh.header.name) validator.escape(req.session.ssh.header.name) - if (req.session.ssh.header.background) validator.escape(req.session.ssh.header.background) }) // express error handling diff --git a/app/server/socket.js b/app/server/socket.js index da880f8..b7a64a0 100644 --- a/app/server/socket.js +++ b/app/server/socket.js @@ -4,44 +4,214 @@ // socket.js // private +var config = require('./config') +var validator = require('validator') var debug = require('debug') +var myutil = require('./util') var debugWebSSH2 = require('debug')('WebSSH2') var SSH = require('ssh2').Client -var CIDRMatcher = require('cidr-matcher'); +var CIDRMatcher = require('cidr-matcher') // var fs = require('fs') // var hostkeys = JSON.parse(fs.readFileSync('./hostkeyhashes.json', 'utf8')) var termCols, termRows var menuData = ' Start Log' + ' Download Log' +// return a subset of keys from an object if they exist +function pick (obj, keys) { + return keys.reduce((acc, key) => { + if (obj[key]) { + acc[key] = obj[key] + } + return acc + }, {}) +} + +const baseSocketConfig = { + host: config.ssh.host, + port: config.ssh.port, + localAddress: config.ssh.localAddress, + localPort: config.ssh.localPort, + term: config.ssh.term, + readyTimeout: config.ssh.readyTimeout, + algorithms: config.algorithms, + keepaliveInterval: config.ssh.keepaliveInterval, + keepaliveCountMax: config.ssh.keepaliveCountMax, + allowedSubnets: config.ssh.allowedSubnets || [], + header: { + name: config.header.text, + background: config.header.background + }, + terminal: { + cursorBlink: config.terminal.cursorBlink, + scrollBack: config.terminal.scrollback, + tabStopWidth: config.terminal.tabStopWidth, + bellStyle: config.terminal.bellStyle + }, + serverlog: { + client: config.serverlog.client || false, + server: config.serverlog.server || false + } +} + +function getValidatedRequestConfig (queryParams) { + const processedParams = {} + const validators = { + host: (host) => validator.isIP(host + '') || validator.isFQDN(host) || /^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(host), + port: (port) => validator.isInt(port + '', { min: 1, max: 65535 }), + sshterm: (sshterm) => /^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(sshterm), + cursorBlink: (cursorBlink) => validator.isBoolean(cursorBlink + ''), + scrollback: (scrollback) => validator.isInt(scrollback + '', { min: 1, max: 200000 }), + tabStopWidth: (tabStopWidth) => validator.isInt(tabStopWidth + '', { min: 1, max: 100 }), + bellStyle: (bellStyle) => (['sound', 'none'].indexOf(bellStyle) > -1), + readyTimeout: (readyTimeout) => validator.isInt(readyTimeout + '', { min: 1, max: 300000 }), + header: () => true, + headerBackground: () => true + } + const transformations = { + cursorBlink: (cursorBlink) => myutil.parseBool(cursorBlink) + } + const rename = { + sshterm: 'term' + } + + // validate & transform and rename query parameters + for (const key in queryParams) { + const value = queryParams[key] + const validator = validators[key] || (() => false) + const transformation = transformations[key] || ((i) => i) + const newName = rename[key] || key + + if (value !== undefined && validator(value)) { + processedParams[newName] = transformation(value) + } + } + + // todo: address all this!! + // const allowreplay = config.options.challengeButton || (validator.isBoolean(req.headers.allowreplay + '') ? myutil.parseBool(req.headers.allowreplay) : false) + // const allowreauth = config.options.allowreauth || false + // const mrhsession = ((validator.isAlphanumeric(req.headers.mrhsession + '') && req.headers.mrhsession) ? req.headers.mrhsession : 'none') + // if (req.session.ssh.header.name) validator.escape(req.session.ssh.header.name) + // if (req.session.ssh.header.background) validator.escape(req.session.ssh.header.background) + // todo: do this when creating base config? + // if (socketConfig.header.name) { + // validator.escape(socketConfig.header.name) + // } + // if (socketConfig.header.background) { + // validator.escape(socketConfig.header.background) + // } + + // create config object from query parameters + const config = pick(processedParams, ['host', 'port', 'readyTimeout', 'term']) + config.terminal = pick(processedParams, ['cursorBlink', 'scrollback', 'tabStopWidth', 'bellStyle']) + config.header = pick(processedParams, ['header', 'headerBackground']) + + return config +} + +function getCredentials (session) { + if (session.username && session.userpassword) { + return { + username: session.username, + userpassword: session.userpassword + } + } else { + return myutil.defaultCredentials + } +} + +/** + * Error handling for various events. Outputs error to client, logs to + * server, destroys session and disconnects socket. + * @param {string} callerName Function calling this function + * @param {object} err Error object or error message + * @param {object} context Additional information about the state when the error occurred + * @param {object} context.socket The socket.io socket object at the time of failure + * @param {object} context.socketConfig The config object based on the base config and the request query parameters + * @param {object} context.credentials The credentials used during the connection that failed + */ +// eslint-disable-next-line complexity +function SSHError (callerName, err, { socket, credentials, socketConfig }) { + var theError + const session = socket.request.session + + if (session) { + // we just want the first error of the session to pass to the client + session.error = session.error || ((err) ? err.message : undefined) + theError = session.error ? ': ' + session.error : '' + + // log unsuccessful login attempt + if (err && (err.level === 'client-authentication')) { + console.log('WebSSH2 ' + 'error: Authentication failure'.red.bold + + ' user=' + credentials.username.yellow.bold.underline + + ' from=' + socket.handshake.address.yellow.bold.underline) + + socket.emit('allowreauth', socketConfig.allowreauth) + socket.emit('reauth') + } else { + console.log('WebSSH2 Logout: user=' + credentials.username + + ' from=' + socket.handshake.address + + ' host=' + socketConfig.host + + ' port=' + socketConfig.port + + ' sessionID=' + socket.request.sessionID + '/' + socket.id + + ' allowreplay=' + socketConfig.allowreplay + + ' term=' + socketConfig.term + ) + if (err) { + theError = err ? ': ' + err.message : '' + console.log('WebSSH2 error' + theError) + } + } + + socket.emit('ssherror', 'SSH ' + callerName + theError) + session.destroy() + } else { + theError = (err) ? ': ' + err.message : '' + } + + socket.disconnect(true) + + debugWebSSH2('SSHError ' + callerName + theError) +} + // public module.exports = function socket (socket) { - // if websocket connection arrives without an express session, kill it - if (!socket.request.session) { - socket.emit('401 UNAUTHORIZED') - debugWebSSH2('SOCKET: No Express Session / REJECTED') + // create new config by merging config object from disk with config object from the request + const socketConfig = Object.assign({}, baseSocketConfig, getValidatedRequestConfig(socket.handshake.query)) + const credentials = getCredentials(socket.request.session) + const hasCredentials = credentials.username && (credentials.userpassword || credentials.privatekey) + const errorContext = { socket, credentials, socketConfig }; + + if (!(hasCredentials && socketConfig)) { + debugWebSSH2('Attempt to connect without session.username/password or session varialbles defined, ' + + 'potentially previously abandoned client session. disconnecting websocket client.\r\n' + + 'Handshake information: \r\n ' + JSON.stringify(socket.handshake)) + socket.emit('ssherror', 'WEBSOCKET ERROR - Refresh the browser and try again') + socket.request.session.destroy() socket.disconnect(true) return } // If configured, check that requsted host is in a permitted subnet - if ( (((socket.request.session || {}).ssh || {}).allowedSubnets || {}).length && ( socket.request.session.ssh.allowedSubnets.length > 0 ) ) { - var matcher = new CIDRMatcher(socket.request.session.ssh.allowedSubnets); - if (!matcher.contains(socket.request.session.ssh.host)) { + if (socketConfig.allowedSubnets.length > 0) { + const matcher = new CIDRMatcher(socketConfig.allowedSubnets) + if (!matcher.contains(socketConfig.host)) { console.log('WebSSH2 ' + 'error: Requested host outside configured subnets / REJECTED'.red.bold + - ' user=' + socket.request.session.username.yellow.bold.underline + - ' from=' + socket.handshake.address.yellow.bold.underline) + ' user=' + credentials.username.yellow.bold.underline + + ' from=' + socket.handshake.address.yellow.bold.underline) socket.emit('ssherror', '401 UNAUTHORIZED') socket.disconnect(true) return } } - var conn = new SSH() + const conn = new SSH() + socket.on('geometry', function socketOnGeometry (cols, rows) { termCols = cols termRows = rows }) + conn.on('banner', function connOnBanner (data) { // need to convert to cr/lf for proper formatting data = data.replace(/\r?\n/g, '\r\n') @@ -49,35 +219,45 @@ module.exports = function socket (socket) { }) conn.on('ready', function connOnReady () { - console.log('WebSSH2 Login: user=' + socket.request.session.username + ' from=' + socket.handshake.address + ' host=' + socket.request.session.ssh.host + ' port=' + socket.request.session.ssh.port + ' sessionID=' + socket.request.sessionID + '/' + socket.id + ' mrhsession=' + socket.request.session.ssh.mrhsession + ' allowreplay=' + socket.request.session.ssh.allowreplay + ' term=' + socket.request.session.ssh.term) + console.log('WebSSH2 Login: user=' + credentials.username + + ' from=' + socket.handshake.address + + ' host=' + socketConfig.host + + ' port=' + socketConfig.port + + ' sessionID=' + socket.request.sessionID + '/' + socket.id + + ' mrhsession=' + socketConfig.mrhsession + + ' allowreplay=' + socketConfig.allowreplay + + ' term=' + socketConfig.term + ) + socket.emit('menu', menuData) - socket.emit('allowreauth', socket.request.session.ssh.allowreauth) - socket.emit('setTerminalOpts', socket.request.session.ssh.terminal) - socket.emit('title', 'ssh://' + socket.request.session.ssh.host) - if (socket.request.session.ssh.header.background) socket.emit('headerBackground', socket.request.session.ssh.header.background) - if (socket.request.session.ssh.header.name) socket.emit('header', socket.request.session.ssh.header.name) - socket.emit('footer', 'ssh://' + socket.request.session.username + '@' + socket.request.session.ssh.host + ':' + socket.request.session.ssh.port) + socket.emit('allowreauth', socketConfig.allowreauth) + socket.emit('setTerminalOpts', socketConfig.terminal) + socket.emit('title', 'ssh://' + socketConfig.host) + if (socketConfig.header.background) socket.emit('headerBackground', socketConfig.header.background) + if (socketConfig.header.name) socket.emit('header', socketConfig.header.name) + socket.emit('footer', 'ssh://' + credentials.username + '@' + socketConfig.host + ':' + socketConfig.port) socket.emit('status', 'SSH CONNECTION ESTABLISHED') socket.emit('statusBackground', 'green') - socket.emit('allowreplay', socket.request.session.ssh.allowreplay) + socket.emit('allowreplay', socketConfig.allowreplay) + conn.shell({ - term: socket.request.session.ssh.term, + term: socketConfig.term, cols: termCols, rows: termRows }, function connShell (err, stream) { if (err) { - SSHerror('EXEC ERROR' + err) + SSHError('EXEC ERROR', err, errorContext) conn.end() return } // poc to log commands from client - if (socket.request.session.ssh.serverlog.client) var dataBuffer + if (socketConfig.serverlog.client) var dataBuffer socket.on('data', function socketOnData (data) { stream.write(data) // poc to log commands from client - if (socket.request.session.ssh.serverlog.client) { + if (socketConfig.serverlog.client) { if (data === '\r') { - console.log('serverlog.client: ' + socket.request.session.id + '/' + socket.id + ' host: ' + socket.request.session.ssh.host + ' command: ' + dataBuffer) + console.log('serverlog.client: ' + socket.request.session.id + '/' + socket.id + ' host: ' + socketConfig.host + ' command: ' + dataBuffer) dataBuffer = undefined } else { dataBuffer = (dataBuffer) ? dataBuffer + data : data @@ -87,8 +267,8 @@ module.exports = function socket (socket) { socket.on('control', function socketOnControl (controlData) { switch (controlData) { case 'replayCredentials': - if (socket.request.session.ssh.allowreplay) { - stream.write(socket.request.session.userpassword + '\n') + if (socketConfig.allowreplay) { + stream.write(credentials.userpassword + '\n') } /* falls through */ default: @@ -102,19 +282,19 @@ module.exports = function socket (socket) { socket.on('disconnect', function socketOnDisconnect (reason) { debugWebSSH2('SOCKET DISCONNECT: ' + reason) err = { message: reason } - SSHerror('CLIENT SOCKET DISCONNECT', err) + SSHError('CLIENT SOCKET DISCONNECT', err, errorContext) conn.end() // socket.request.session.destroy() }) socket.on('error', function socketOnError (err) { - SSHerror('SOCKET ERROR', err) + SSHError('SOCKET ERROR', err, errorContext) conn.end() }) stream.on('data', function streamOnData (data) { socket.emit('data', data.toString('utf-8')) }) stream.on('close', function streamOnClose (code, signal) { err = { message: ((code || signal) ? (((code) ? 'CODE: ' + code : '') + ((code && signal) ? ' ' : '') + ((signal) ? 'SIGNAL: ' + signal : '')) : undefined) } - SSHerror('STREAM CLOSE', err) + SSHError('STREAM CLOSE', err, errorContext) conn.end() }) stream.stderr.on('data', function streamStderrOnData (data) { @@ -123,71 +303,28 @@ 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('error', function connOnError (err) { SSHerror('CONN ERROR', err) }) + conn.on('end', function connOnEnd (err) { SSHError('CONN END BY HOST', err, errorContext) }) + conn.on('close', function connOnClose (err) { SSHError('CONN CLOSE', err, errorContext) }) + conn.on('error', function connOnError (err) { SSHError('CONN ERROR', err, errorContext) }) conn.on('keyboard-interactive', function connOnKeyboardInteractive (name, instructions, instructionsLang, prompts, finish) { debugWebSSH2('conn.on(\'keyboard-interactive\')') - finish([socket.request.session.userpassword]) + finish([credentials.userpassword]) }) - 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, - port: socket.request.session.ssh.port, - localAddress: socket.request.session.ssh.localAddress, - 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, - keepaliveInterval: socket.request.session.ssh.keepaliveInterval, - keepaliveCountMax: socket.request.session.ssh.keepaliveCountMax, - debug: debug('ssh2') - }) - } else { - debugWebSSH2('Attempt to connect without session.username/password or session varialbles defined, potentially previously abandoned client session. disconnecting websocket client.\r\nHandshake information: \r\n ' + JSON.stringify(socket.handshake)) - socket.emit('ssherror', 'WEBSOCKET ERROR - Refresh the browser and try again') - socket.request.session.destroy() - socket.disconnect(true) - } - /** - * Error handling for various events. Outputs error to client, logs to - * server, destroys session and disconnects 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) { - // we just want the first error of the session to pass to the client - socket.request.session.error = (socket.request.session.error) || ((err) ? err.message : undefined) - theError = (socket.request.session.error) ? ': ' + socket.request.session.error : '' - // log unsuccessful login attempt - if (err && (err.level === 'client-authentication')) { - console.log('WebSSH2 ' + 'error: Authentication failure'.red.bold + - ' user=' + socket.request.session.username.yellow.bold.underline + - ' from=' + socket.handshake.address.yellow.bold.underline) - socket.emit('allowreauth', socket.request.session.ssh.allowreauth) - socket.emit('reauth') - } else { - console.log('WebSSH2 Logout: user=' + socket.request.session.username + ' from=' + socket.handshake.address + ' host=' + socket.request.session.ssh.host + ' port=' + socket.request.session.ssh.port + ' sessionID=' + socket.request.sessionID + '/' + socket.id + ' allowreplay=' + socket.request.session.ssh.allowreplay + ' term=' + socket.request.session.ssh.term) - if (err) { - theError = (err) ? ': ' + err.message : '' - console.log('WebSSH2 error' + theError) - } - } - socket.emit('ssherror', 'SSH ' + myFunc + theError) - socket.request.session.destroy() - socket.disconnect(true) - } else { - theError = (err) ? ': ' + err.message : '' - socket.disconnect(true) - } - debugWebSSH2('SSHerror ' + myFunc + theError) - } + // console.log('hostkeys: ' + hostkeys[0].[0]) + conn.connect({ + host: socketConfig.host, + port: socketConfig.port, + localAddress: socketConfig.localAddress, + localPort: socketConfig.localPort, + username: credentials.username, + password: credentials.userpassword, + privateKey: credentials.privatekey, + tryKeyboard: true, + algorithms: socketConfig.algorithms, + readyTimeout: socketConfig.readyTimeout, + keepaliveInterval: socketConfig.keepaliveInterval, + keepaliveCountMax: socketConfig.keepaliveCountMax, + debug: debug('ssh2') + }) } diff --git a/app/server/util.js b/app/server/util.js index 0ca3dca..a9357d0 100644 --- a/app/server/util.js +++ b/app/server/util.js @@ -4,37 +4,36 @@ // private require('colors') // allow for color property extensions in log messages +var config = require('./config') var debug = require('debug')('WebSSH2') var Auth = require('basic-auth') -let defaultCredentials = {username: null, password: null, privatekey: null}; - -exports.setDefaultCredentials = function (username, password, privatekey) { - defaultCredentials.username = username - defaultCredentials.password = password - defaultCredentials.privatekey = privatekey +exports.defaultCredentials = { + username: config.user.name, + userpassword: config.user.password, + privatekey: config.user.privatekey, } exports.basicAuth = function basicAuth (req, res, next) { var myAuth = Auth(req) + let password = exports.defaultCredentials.userpassword + if (myAuth && myAuth.pass !== '') { req.session.username = myAuth.name - req.session.userpassword = myAuth.pass + req.session.userpassword = password = myAuth.pass debug('myAuth.name: ' + myAuth.name.yellow.bold.underline + ' and password ' + ((myAuth.pass) ? 'exists'.yellow.bold.underline : 'is blank'.underline.red.bold)) - } else { - req.session.username = defaultCredentials.username; - req.session.userpassword = defaultCredentials.password; - req.session.privatekey = defaultCredentials.privatekey; } - if ( (!req.session.userpassword) && (!req.session.privatekey) ) { + + if (!(password || exports.defaultCredentials.privatekey)) { res.statusCode = 401 debug('basicAuth credential request (401)') res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"') res.end('Username and password required for web SSH service.') return } + next() }