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() }