chore: template keyboard-interactive
This commit is contained in:
parent
2bd225e12e
commit
0899cb0efa
3 changed files with 164 additions and 6 deletions
85
app/ssh.js
85
app/ssh.js
|
@ -8,12 +8,24 @@ const { maskSensitiveData } = require("./utils")
|
||||||
|
|
||||||
const debug = createNamespacedDebug("ssh")
|
const debug = createNamespacedDebug("ssh")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSHConnection class handles SSH connections and operations.
|
||||||
|
* @class
|
||||||
|
* @param {Object} config - Configuration object for the SSH connection.
|
||||||
|
*/
|
||||||
function SSHConnection(config) {
|
function SSHConnection(config) {
|
||||||
this.config = config
|
this.config = config
|
||||||
this.conn = null
|
this.conn = null
|
||||||
this.stream = null
|
this.stream = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the SSH server using the provided credentials.
|
||||||
|
* @function
|
||||||
|
* @memberof SSHConnection
|
||||||
|
* @param {Object} creds - The credentials object containing host, port, username, and password.
|
||||||
|
* @returns {Promise<SSH>} - A promise that resolves with the SSH connection instance.
|
||||||
|
*/
|
||||||
SSHConnection.prototype.connect = function(creds) {
|
SSHConnection.prototype.connect = function(creds) {
|
||||||
debug("connect: %O", maskSensitiveData(creds))
|
debug("connect: %O", maskSensitiveData(creds))
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -38,14 +50,66 @@ SSHConnection.prototype.connect = function(creds) {
|
||||||
reject(error)
|
reject(error)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.conn.on(
|
||||||
|
"keyboard-interactive",
|
||||||
|
(name, instructions, lang, prompts, finish) => {
|
||||||
|
this.handleKeyboardInteractive(
|
||||||
|
creds,
|
||||||
|
name,
|
||||||
|
instructions,
|
||||||
|
lang,
|
||||||
|
prompts,
|
||||||
|
finish
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
this.conn.connect(sshConfig)
|
this.conn.connect(sshConfig)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the SSH configuration
|
* Handles keyboard-interactive authentication prompts.
|
||||||
* @param {Object} creds - The credentials object
|
* @function
|
||||||
* @returns {Object} The SSH configuration object
|
* @memberof SSHConnection
|
||||||
|
* @param {Object} creds - The credentials object containing password.
|
||||||
|
* @param {string} name - The name of the authentication request.
|
||||||
|
* @param {string} instructions - The instructions for the keyboard-interactive prompt.
|
||||||
|
* @param {string} lang - The language of the prompt.
|
||||||
|
* @param {Array<Object>} prompts - The list of prompts provided by the server.
|
||||||
|
* @param {Function} finish - The callback to complete the keyboard-interactive authentication.
|
||||||
|
*/
|
||||||
|
SSHConnection.prototype.handleKeyboardInteractive = function(
|
||||||
|
creds,
|
||||||
|
name,
|
||||||
|
instructions,
|
||||||
|
lang,
|
||||||
|
prompts,
|
||||||
|
finish
|
||||||
|
) {
|
||||||
|
debug("handleKeyboardInteractive: Keyboard-interactive auth %O", prompts)
|
||||||
|
const responses = []
|
||||||
|
|
||||||
|
for (let i = 0; i < prompts.length; i += 1) {
|
||||||
|
if (prompts[i].prompt.toLowerCase().includes("password")) {
|
||||||
|
responses.push(creds.password)
|
||||||
|
} else {
|
||||||
|
// todo: For any non-password prompts, we meed to implement a way to
|
||||||
|
// get responses from the user through a modal. For now, we'll just
|
||||||
|
// send an empty string
|
||||||
|
responses.push("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finish(responses)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the SSH configuration object based on credentials.
|
||||||
|
* @function
|
||||||
|
* @memberof SSHConnection
|
||||||
|
* @param {Object} creds - The credentials object containing host, port, username, and password.
|
||||||
|
* @returns {Object} - The SSH configuration object.
|
||||||
*/
|
*/
|
||||||
SSHConnection.prototype.getSSHConfig = function(creds) {
|
SSHConnection.prototype.getSSHConfig = function(creds) {
|
||||||
return {
|
return {
|
||||||
|
@ -62,6 +126,13 @@ SSHConnection.prototype.getSSHConfig = function(creds) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an interactive shell session over the SSH connection.
|
||||||
|
* @function
|
||||||
|
* @memberof SSHConnection
|
||||||
|
* @param {Object} [options] - Optional parameters for the shell.
|
||||||
|
* @returns {Promise<Object>} - A promise that resolves with the SSH shell stream.
|
||||||
|
*/
|
||||||
SSHConnection.prototype.shell = function(options) {
|
SSHConnection.prototype.shell = function(options) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.conn.shell(options, (err, stream) => {
|
this.conn.shell(options, (err, stream) => {
|
||||||
|
@ -76,9 +147,11 @@ SSHConnection.prototype.shell = function(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the terminal
|
* Resizes the terminal window for the current SSH session.
|
||||||
* @param {number} rows - The number of rows
|
* @function
|
||||||
* @param {number} cols - The number of columns
|
* @memberof SSHConnection
|
||||||
|
* @param {number} rows - The number of rows for the terminal.
|
||||||
|
* @param {number} cols - The number of columns for the terminal.
|
||||||
*/
|
*/
|
||||||
SSHConnection.prototype.resizeTerminal = function(rows, cols) {
|
SSHConnection.prototype.resizeTerminal = function(rows, cols) {
|
||||||
if (this.stream) {
|
if (this.stream) {
|
||||||
|
|
27
tests/servers/keyboard-interactive/Dockerfile
Normal file
27
tests/servers/keyboard-interactive/Dockerfile
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Use the Debian Bullseye Slim image as the base
|
||||||
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
|
# Install the necessary packages
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
openssh-server && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Configure SSH server
|
||||||
|
RUN mkdir /var/run/sshd && \
|
||||||
|
sed -i 's/^ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config && \
|
||||||
|
echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config && \
|
||||||
|
echo 'Port 4444' >> /etc/ssh/sshd_config && \
|
||||||
|
echo 'UsePAM yes' >> /etc/ssh/sshd_config && \
|
||||||
|
echo 'AuthenticationMethods keyboard-interactive' >> /etc/ssh/sshd_config
|
||||||
|
|
||||||
|
# Add a test user with a password
|
||||||
|
RUN useradd -m testuser && \
|
||||||
|
echo "testuser:testpassword" | chpasswd
|
||||||
|
|
||||||
|
# Expose port 4444
|
||||||
|
EXPOSE 4444
|
||||||
|
|
||||||
|
# Start the SSH server
|
||||||
|
CMD ["/usr/sbin/sshd", "-D", "-e", "-d", "-d", "-d"]
|
58
tests/servers/keyboard-interactive/README.md
Normal file
58
tests/servers/keyboard-interactive/README.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
# Keyboard Interactive SSH Server
|
||||||
|
A test SSH server that uses keyboard-interactive authentication and listens on port 4444:
|
||||||
|
|
||||||
|
```Dockerfile
|
||||||
|
# Use the Debian Bullseye Slim image as the base
|
||||||
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
|
# Install the necessary packages
|
||||||
|
# Use the Debian Bullseye Slim image as the base
|
||||||
|
FROM debian:bullseye-slim
|
||||||
|
|
||||||
|
# Install the necessary packages
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
openssh-server && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Configure SSH server
|
||||||
|
RUN mkdir /var/run/sshd && \
|
||||||
|
sed -i 's/^ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config && \
|
||||||
|
echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config && \
|
||||||
|
echo 'Port 4444' >> /etc/ssh/sshd_config && \
|
||||||
|
echo 'UsePAM yes' >> /etc/ssh/sshd_config && \
|
||||||
|
echo 'AuthenticationMethods keyboard-interactive' >> /etc/ssh/sshd_config
|
||||||
|
|
||||||
|
# Add a test user with a password
|
||||||
|
RUN useradd -m testuser && \
|
||||||
|
echo "testuser:testpassword" | chpasswd
|
||||||
|
|
||||||
|
# Expose port 4444
|
||||||
|
EXPOSE 4444
|
||||||
|
|
||||||
|
# Start the SSH server
|
||||||
|
CMD ["/usr/sbin/sshd", "-D", "-e", "-d -d -d"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Instructions:
|
||||||
|
|
||||||
|
1. **Build the Docker image**:
|
||||||
|
```bash
|
||||||
|
docker build -t keyboard-ssh-server .
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Run the container**:
|
||||||
|
```bash
|
||||||
|
docker run --rm -p 4444:4444 --name keyboard-ssh-server keyboard-ssh-server
|
||||||
|
```
|
||||||
|
|
||||||
|
This Dockerfile sets up an SSH server that listens on port 4444 and uses keyboard-interactive authentication. The `testuser` has been created with the password `testpassword`.
|
||||||
|
|
||||||
|
You can connect to this SSH server using the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -p 4444 testuser@localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll be prompted for a password as part of the keyboard-interactive authentication process.
|
Loading…
Reference in a new issue