feat: Switch User or reauth feature for Basic Auth sessions

This commit is contained in:
Bill Church 2024-08-19 18:51:07 +00:00
parent 96ee27fe2b
commit a530f59704
No known key found for this signature in database
5 changed files with 37 additions and 10 deletions

View file

@ -45,6 +45,22 @@ function createApp() {
app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json()) app.use(bodyParser.json())
// Add cookie-setting middleware
app.use((req, res, next) => {
if (req.session.sshCredentials) {
const cookieData = {
host: req.session.sshCredentials.host,
port: req.session.sshCredentials.port
}
res.cookie("basicauth", JSON.stringify(cookieData), {
httpOnly: false,
path: '/ssh/host/',
sameSite: 'Strict'
}) // ensure httOnly is false for the client to read the cookie
}
next()
})
// Serve static files from the webssh2_client module with a custom prefix // Serve static files from the webssh2_client module with a custom prefix
app.use("/ssh/assets", express.static(clientPath)) app.use("/ssh/assets", express.static(clientPath))

View file

@ -282,22 +282,28 @@ function loadConfig() {
providedConfig providedConfig
) )
// Override the port with the PORT environment variable if it's set
if (process.env.PORT) {
mergedConfig.listen.port = parseInt(process.env.PORT, 10)
console.log(`Using PORT from environment: ${mergedConfig.listen.port}`)
}
const validatedConfig = validateConfig(mergedConfig) const validatedConfig = validateConfig(mergedConfig)
console.log("Merged and validated configuration") console.log('Merged and validated configuration')
return validatedConfig return validatedConfig
} else { } else {
logError( logError(
"\n\nERROR: Missing config.json for webssh. Using default config: " + '\n\nERROR: Missing config.json for webssh. Using default config: ' +
JSON.stringify(defaultConfig) + JSON.stringify(defaultConfig) +
"\n\n See config.json.sample for details\n\n" '\n\n See config.json.sample for details\n\n'
) )
return defaultConfig return defaultConfig
} }
} catch (err) { } catch (err) {
logError( logError(
"\n\nERROR: Problem loading config.json for webssh. Using default config: " + '\n\nERROR: Problem loading config.json for webssh. Using default config: ' +
JSON.stringify(defaultConfig) + JSON.stringify(defaultConfig) +
"\n\n See config.json.sample for details\n\n", '\n\n See config.json.sample for details\n\n',
err err
) )
return defaultConfig return defaultConfig

View file

@ -28,7 +28,8 @@ function handleConnection(req, res, urlParams) {
} }
// Check if the current route is /host/:host // Check if the current route is /host/:host
if (req.path.startsWith('/ssh/host/')) { debug('handleConnection req.path:', req.path)
if (req.path.startsWith('/host/')) {
tempConfig.autoConnect = true tempConfig.autoConnect = true
} }

View file

@ -10,7 +10,7 @@ const { sanitizeObject, validateSshTerm } = require("./utils")
const validator = require("validator") const validator = require("validator")
function auth(req, res, next) { function auth(req, res, next) {
debug("Authenticating user with HTTP Basic Auth") debug("auth: 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"')
@ -21,6 +21,7 @@ function auth(req, res, next) {
username: validator.escape(credentials.name), username: validator.escape(credentials.name),
password: credentials.pass // We don't sanitize the password as it might contain special characters password: credentials.pass // We don't sanitize the password as it might contain special characters
} }
req.session.usedBasicAuth = true // Set this flag when Basic Auth is used
next() next()
} }
@ -59,6 +60,7 @@ router.get("/host/:host", auth, function (req, res) {
if (req.query.sshTerm) { if (req.query.sshTerm) {
req.session.sshCredentials.term = sshTerm req.session.sshCredentials.term = sshTerm
} }
req.session.usedBasicAuth = true
// Sanitize and log the sshCredentials object // Sanitize and log the sshCredentials object
const sanitizedCredentials = sanitizeObject( const sanitizedCredentials = sanitizeObject(
@ -70,12 +72,12 @@ router.get("/host/:host", auth, function (req, res) {
}) })
// Clear credentials route // Clear credentials route
router.post("/clear-credentials", function (req, res) { router.get("/clear-credentials", function (req, res) {
req.session.sshCredentials = null req.session.sshCredentials = null
res.status(200).send("Credentials cleared.") res.status(200).send("Credentials cleared.")
}) })
router.post("/force-reconnect", function (req, res) { router.get("/force-reconnect", function (req, res) {
req.session.sshCredentials = null req.session.sshCredentials = null
res.status(401).send("Authentication required.") res.status(401).send("Authentication required.")
}) })

View file

@ -371,6 +371,7 @@ module.exports = function (io, config) {
socket.handshake.session.sshCredentials.username = null socket.handshake.session.sshCredentials.username = null
socket.handshake.session.sshCredentials.password = null socket.handshake.session.sshCredentials.password = null
} }
socket.handshake.session.usedBasicAuth = false
sessionState.authenticated = false sessionState.authenticated = false
sessionState.username = null sessionState.username = null
sessionState.password = null sessionState.password = null
@ -382,7 +383,8 @@ module.exports = function (io, config) {
} }
// Check for HTTP Basic Auth credentials // Check for HTTP Basic Auth credentials
if (socket.handshake.session.sshCredentials) { if (socket.handshake.session.usedBasicAuth && socket.handshake.session.sshCredentials) {
// if (socket.handshake.session.sshCredentials) {
var creds = socket.handshake.session.sshCredentials var creds = socket.handshake.session.sshCredentials
debug( debug(
"handleConnection: " + "handleConnection: " +