fix: handle http basic auth in /ssh/host/ route

This commit is contained in:
Bill Church 2024-08-13 14:30:32 +00:00
parent aa633aef0b
commit 1fc35f74da
No known key found for this signature in database
3 changed files with 81 additions and 41 deletions

View file

@ -7,56 +7,53 @@ var extend = require("util")._extend
function handleConnection(req, res, urlParams) { function handleConnection(req, res, urlParams) {
urlParams = urlParams || {} urlParams = urlParams || {}
// The path to the client directory of the webssh2 module. const clientPath = path.resolve(
var clientPath = path.resolve(
__dirname, __dirname,
"..", '..',
"node_modules", 'node_modules',
"webssh2_client", 'webssh2_client',
"client", 'client',
"public" 'public'
) )
// Combine URL parameters, query parameters, and form data const connectionParams = extend({}, urlParams)
var connectionParams = extend({}, urlParams)
extend(connectionParams, req.query) extend(connectionParams, req.query)
extend(connectionParams, req.body || {}) extend(connectionParams, req.body || {})
// Inject configuration const sshCredentials = req.session.sshCredentials || {}
var config = {
const config = {
socket: { socket: {
url: req.protocol + "://" + req.get("host"), url: req.protocol + '://' + req.get('host'),
path: "/ssh/socket.io" path: '/ssh/socket.io'
}, },
ssh: { ssh: {
host: urlParams.host || "", host: urlParams.host || sshCredentials.host || '',
port: urlParams.port || 22 port: urlParams.port || sshCredentials.port || 22,
username: sshCredentials.username || '',
password: sshCredentials.password || ''
}, },
autoConnect: !!req.session.sshCredentials autoConnect: !!req.session.sshCredentials
} }
// Read the client.htm file
fs.readFile( fs.readFile(
path.join(clientPath, "client.htm"), path.join(clientPath, 'client.htm'),
"utf8", 'utf8',
function (err, data) { function (err, data) {
if (err) { if (err) {
return res.status(500).send("Error loading client file") return res.status(500).send('Error loading client file')
} }
// Replace relative paths with the correct path
var modifiedHtml = data.replace( var modifiedHtml = data.replace(
/(src|href)="(?!http|\/\/)/g, /(src|href)="(?!http|\/\/)/g,
'$1="/ssh/assets/' '$1="/ssh/assets/'
) )
// Inject the configuration into the HTML
modifiedHtml = modifiedHtml.replace( modifiedHtml = modifiedHtml.replace(
"window.webssh2Config = null;", 'window.webssh2Config = null;',
"window.webssh2Config = " + JSON.stringify(config) + ";" 'window.webssh2Config = ' + JSON.stringify(config) + ';'
) )
// Send the modified HTML
res.send(modifiedHtml) res.send(modifiedHtml)
} }
) )

View file

@ -1,34 +1,48 @@
// server // server
// /app/routes.js // /app/routes.js
const createDebug = require("debug") const createDebug = require('debug')
const debug = createDebug("webssh2:routes") const debug = createDebug('webssh2:routes')
const express = require("express") const express = require('express')
const router = express.Router() const router = express.Router()
const handleConnection = require("./connectionHandler") const handleConnection = require('./connectionHandler')
const basicAuth = require("basic-auth") const basicAuth = require('basic-auth')
function auth(req, res, next) { function auth(req, res, next) {
debug("Authenticating user with HTTP Basic Auth") debug('Authenticating user with HTTP Basic Auth')
var credentials = basicAuth(req) var credentials = basicAuth(req)
if (!credentials) { if (!credentials) {
res.setHeader("WWW-Authenticate", 'Basic realm="WebSSH2"') res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH2"')
return res.status(401).send("Authentication required.") return res.status(401).send('Authentication required.')
} }
// Store credentials in session // Store credentials in session
req.session.sshCredentials = credentials req.session.sshCredentials = {
username: credentials.name,
password: credentials.pass
}
next() next()
} }
// Scenario 1: No auth required, uses websocket authentication instead // Scenario 1: No auth required, uses websocket authentication instead
router.get("/", function (req, res) { router.get('/', function (req, res) {
debug("Accessed /ssh route") debug('Accessed / route')
handleConnection(req, res) handleConnection(req, res)
}) })
// Scenario 2: Auth required, uses HTTP Basic Auth // Scenario 2: Auth required, uses HTTP Basic Auth
router.get("/host/:host", auth, function (req, res) { router.get('/host/:host', auth, function (req, res) {
debug(`Accessed /ssh/host/${req.params.host} route`) debug(`Accessed /ssh/host/${req.params.host} route`)
handleConnection(req, res, { host: req.params.host }) handleConnection(req, res, { host: req.params.host })
}) })
// Clear credentials route
router.post('/clear-credentials', function (req, res) {
req.session.sshCredentials = null
res.status(200).send('Credentials cleared.')
})
router.post("/force-reconnect", function (req, res) {
req.session.sshCredentials = null;
res.status(401).send("Authentication required.");
});
module.exports = router module.exports = router

View file

@ -86,12 +86,27 @@ function handleConnection(socket, config) {
* @param {Object} config - The configuration object * @param {Object} config - The configuration object
*/ */
function handleAuthentication(socket, creds, config) { function handleAuthentication(socket, creds, config) {
debug(`AUTHENTICATE: ${socket.id}, Host: ${creds.host}`) // If reauth, creds from this function should take precedence
if (creds && isValidCredentials(creds)) {
// Store new credentials in session, overriding any existing ones
socket.handshake.session.sshCredentials = {
username: creds.username,
password: creds.password,
host: creds.host,
port: creds.port
}
if (isValidCredentials(creds)) { // Save the session after updating
debug(`CREDENTIALS VALID: ${socket.id}, Host: ${creds.host}`) socket.handshake.session.save((err) => {
if (err) {
console.error(`Failed to save session for ${socket.id}:`, err)
}
})
// Proceed with connection initialization using the new credentials
initializeConnection(socket, creds, config) initializeConnection(socket, creds, config)
} else { } else {
// Handle invalid credentials scenario
debug(`CREDENTIALS INVALID: ${socket.id}, Host: ${creds.host}`) debug(`CREDENTIALS INVALID: ${socket.id}, Host: ${creds.host}`)
socket.emit("authentication", { socket.emit("authentication", {
success: false, success: false,
@ -331,8 +346,22 @@ function handleConnection(socket, config) {
*/ */
function handleReauth(socket) { function handleReauth(socket) {
debug(`Reauthentication requested for ${socket.id}`) debug(`Reauthentication requested for ${socket.id}`)
socket.emit("authentication", { action: "reauth" })
handleConnectionClose(socket) // Clear existing session credentials
socket.handshake.session.sshCredentials = null
// Save the session after modification
socket.handshake.session.save((err) => {
if (err) {
console.error(`Failed to save session for ${socket.id}:`, err)
}
// Notify client to reauthenticate
socket.emit("authentication", { action: "reauth" })
// Close the current connection to enforce reauthentication
handleConnectionClose(socket)
})
} }
/** /**