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

View file

@ -1,34 +1,48 @@
// server
// /app/routes.js
const createDebug = require("debug")
const debug = createDebug("webssh2:routes")
const express = require("express")
const createDebug = require('debug')
const debug = createDebug('webssh2:routes')
const express = require('express')
const router = express.Router()
const handleConnection = require("./connectionHandler")
const basicAuth = require("basic-auth")
const handleConnection = require('./connectionHandler')
const basicAuth = require('basic-auth')
function auth(req, res, next) {
debug("Authenticating user with HTTP Basic Auth")
debug('Authenticating user with HTTP Basic Auth')
var credentials = basicAuth(req)
if (!credentials) {
res.setHeader("WWW-Authenticate", 'Basic realm="WebSSH2"')
return res.status(401).send("Authentication required.")
res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH2"')
return res.status(401).send('Authentication required.')
}
// Store credentials in session
req.session.sshCredentials = credentials
req.session.sshCredentials = {
username: credentials.name,
password: credentials.pass
}
next()
}
// Scenario 1: No auth required, uses websocket authentication instead
router.get("/", function (req, res) {
debug("Accessed /ssh route")
router.get('/', function (req, res) {
debug('Accessed / route')
handleConnection(req, res)
})
// 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`)
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

View file

@ -86,12 +86,27 @@ function handleConnection(socket, config) {
* @param {Object} config - The configuration object
*/
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)) {
debug(`CREDENTIALS VALID: ${socket.id}, Host: ${creds.host}`)
// Save the session after updating
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)
} else {
// Handle invalid credentials scenario
debug(`CREDENTIALS INVALID: ${socket.id}, Host: ${creds.host}`)
socket.emit("authentication", {
success: false,
@ -331,8 +346,22 @@ function handleConnection(socket, config) {
*/
function handleReauth(socket) {
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)
})
}
/**