Skip to content

Commit

Permalink
fix: username/password in config file no longer honored #374
Browse files Browse the repository at this point in the history
  • Loading branch information
billchurch committed Nov 21, 2024
1 parent eb8f620 commit 4185df7
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nodejs 6.9.1
nodejs 23.2.0
2 changes: 1 addition & 1 deletion app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
const express = require("express")
const config = require("./config")
const socketHandler = require("./socket")
const sshRoutes = require("./routes")
const sshRoutes = require("./routes")(config)
const { applyMiddleware } = require("./middleware")
const { createServer, startServer } = require("./server")
const { configureSocketIO } = require("./io")
Expand Down
144 changes: 87 additions & 57 deletions app/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,72 +16,102 @@ const { ConfigError, handleError } = require("./errors")
const { HTTP } = require("./constants")

const debug = createNamespacedDebug("routes")
const router = express.Router()

// eslint-disable-next-line consistent-return
function auth(req, res, next) {
debug("auth: Basic Auth")
const credentials = basicAuth(req)
if (!credentials) {
res.setHeader(HTTP.AUTHENTICATE, HTTP.REALM)
return res.status(HTTP.UNAUTHORIZED).send(HTTP.AUTH_REQUIRED)
}
// Validate and sanitize credentials
req.session.sshCredentials = {
username: validator.escape(credentials.name),
password: credentials.pass // We don't sanitize the password as it might contain special characters
module.exports = function(config) {
const router = express.Router()

/**
* Middleware function that handles HTTP Basic Authentication for the application.
*
* If the `config.user.name` and `config.user.password` are set, it will use those
* credentials to authenticate the request and set the `req.session.sshCredentials`
* object with the username and password.
*
* If the `config.user.name` and `config.user.password` are not set, it will attempt
* to use HTTP Basic Authentication to authenticate the request. It will validate and
* sanitize the credentials, and set the `req.session.sshCredentials` object with the
* username and password.
*
* The function will also set the `req.session.usedBasicAuth` flag to indicate that
* Basic Authentication was used.
*
* If the authentication fails, the function will send a 401 Unauthorized response
* with the appropriate WWW-Authenticate header.
*/
// eslint-disable-next-line consistent-return
function auth(req, res, next) {
if (config.user.name && config.user.password) {
req.session.sshCredentials = {
username: config.user.name,
password: config.user.password
}
req.session.usedBasicAuth = true
return next()
}
// Scenario 2: Basic Auth
debug("auth: Basic Auth")
const credentials = basicAuth(req)
if (!credentials) {
res.setHeader(HTTP.AUTHENTICATE, HTTP.REALM)
return res.status(HTTP.UNAUTHORIZED).send(HTTP.AUTH_REQUIRED)
}
// Validate and sanitize credentials
req.session.sshCredentials = {
username: validator.escape(credentials.name),
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()
}
req.session.usedBasicAuth = true // Set this flag when Basic Auth is used
next()
}

// Scenario 1: No auth required, uses websocket authentication instead
router.get("/", (req, res) => {
debug("router.get./: Accessed / route")
handleConnection(req, res)
})
// Scenario 1: No auth required, uses websocket authentication instead
router.get("/", (req, res) => {
debug("router.get./: Accessed / route")
handleConnection(req, res)
})

// Scenario 2: Auth required, uses HTTP Basic Auth
router.get("/host/:host", auth, (req, res) => {
debug(`router.get.host: /ssh/host/${req.params.host} route`)
// Scenario 2: Auth required, uses HTTP Basic Auth
router.get("/host/:host", auth, (req, res) => {
debug(`router.get.host: /ssh/host/${req.params.host} route`)

try {
const host = getValidatedHost(req.params.host)
const port = getValidatedPort(req.query.port)
try {
const host = getValidatedHost(req.params.host)
const port = getValidatedPort(req.query.port)

// Validate and sanitize sshterm parameter if it exists
const sshterm = validateSshTerm(req.query.sshterm)
// Validate and sanitize sshterm parameter if it exists
const sshterm = validateSshTerm(req.query.sshterm)

req.session.sshCredentials = req.session.sshCredentials || {}
req.session.sshCredentials.host = host
req.session.sshCredentials.port = port
if (req.query.sshterm) {
req.session.sshCredentials.term = sshterm
}
req.session.usedBasicAuth = true
req.session.sshCredentials = req.session.sshCredentials || {}
req.session.sshCredentials.host = host
req.session.sshCredentials.port = port
if (req.query.sshterm) {
req.session.sshCredentials.term = sshterm
}
req.session.usedBasicAuth = true

// Sanitize and log the sshCredentials object
const sanitizedCredentials = maskSensitiveData(
JSON.parse(JSON.stringify(req.session.sshCredentials))
)
debug("/ssh/host/ Credentials: ", sanitizedCredentials)
// Sanitize and log the sshCredentials object
const sanitizedCredentials = maskSensitiveData(
JSON.parse(JSON.stringify(req.session.sshCredentials))
)
debug("/ssh/host/ Credentials: ", sanitizedCredentials)

handleConnection(req, res, { host: host })
} catch (err) {
const error = new ConfigError(`Invalid configuration: ${err.message}`)
handleError(error, res)
}
})
handleConnection(req, res, { host: host })
} catch (err) {
const error = new ConfigError(`Invalid configuration: ${err.message}`)
handleError(error, res)
}
})

// Clear credentials route
router.get("/clear-credentials", (req, res) => {
req.session.sshCredentials = null
res.status(HTTP.OK).send(HTTP.CREDENTIALS_CLEARED)
})
// Clear credentials route
router.get("/clear-credentials", (req, res) => {
req.session.sshCredentials = null
res.status(HTTP.OK).send(HTTP.CREDENTIALS_CLEARED)
})

router.get("/force-reconnect", (req, res) => {
req.session.sshCredentials = null
res.status(HTTP.UNAUTHORIZED).send(HTTP.AUTH_REQUIRED)
})
router.get("/force-reconnect", (req, res) => {
req.session.sshCredentials = null
res.status(HTTP.UNAUTHORIZED).send(HTTP.AUTH_REQUIRED)
})

module.exports = router
return router
}

0 comments on commit 4185df7

Please sign in to comment.