feat: accept private key from client #381
This commit is contained in:
parent
b511ce5eae
commit
829b5cdd75
9 changed files with 24 additions and 29 deletions
|
@ -84,7 +84,7 @@ Renamed and expanded options:
|
|||
## Detailed Changes
|
||||
|
||||
### 1. Authentication Options
|
||||
- Added support for SSH private key authentication via `user.privatekey`
|
||||
- Added support for SSH private key authentication via `user.privateKey`
|
||||
- Removed `user.overridebasic` option
|
||||
- Added keyboard-interactive authentication controls
|
||||
|
||||
|
@ -128,7 +128,7 @@ These settings are now managed client-side.
|
|||
"user": {
|
||||
"name": null,
|
||||
"password": null,
|
||||
"privatekey": null
|
||||
"privateKey": null
|
||||
},
|
||||
"ssh": {
|
||||
"host": null,
|
||||
|
|
|
@ -115,7 +115,7 @@ Edit `config.json` to customize the following options:
|
|||
- `user.name` - _string_ - Default SSH username (default: `null`)
|
||||
- `user.password` - _string_ - Default SSH password (default: `null`)
|
||||
- `ssh.host` - _string_ - Default SSH host (default: `null`)
|
||||
- `user.privatekey` - _string_ - Default SSH private key (default: `null`)
|
||||
- `user.privateKey` - _string_ - Default SSH private key (default: `null`)
|
||||
- `ssh.port` - _integer_ - Default SSH port (default: `22`)
|
||||
- `ssh.term` - _string_ - Terminal emulation (default: `"xterm-color"`)
|
||||
- `ssh.readyTimeout` - _integer_ - SSH handshake timeout in ms (default: `20000`)
|
||||
|
@ -206,7 +206,7 @@ Private key authentication can only be configured through the `config.json` file
|
|||
{
|
||||
"user": {
|
||||
"name": "myuser",
|
||||
"privatekey": "-----BEGIN RSA PRIVATE KEY-----\nYour-Private-Key-Here\n-----END RSA PRIVATE KEY-----",
|
||||
"privateKey": "-----BEGIN RSA PRIVATE KEY-----\nYour-Private-Key-Here\n-----END RSA PRIVATE KEY-----",
|
||||
"password": "optional-fallback-password"
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ This command:
|
|||
{
|
||||
"user": {
|
||||
"name": "myuser",
|
||||
"privatekey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpA...[rest of key]...Yh5Q==\n-----END RSA PRIVATE KEY-----",
|
||||
"privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpA...[rest of key]...Yh5Q==\n-----END RSA PRIVATE KEY-----",
|
||||
"password": "fallback-password"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ const configSchema = {
|
|||
type: "object",
|
||||
properties: {
|
||||
name: { type: ["string", "null"] },
|
||||
password: { type: ["string", "null"] }
|
||||
password: { type: ["string", "null"] },
|
||||
privateKey: { type: ["string", "null"] }
|
||||
},
|
||||
required: ["name", "password"]
|
||||
},
|
||||
|
@ -39,7 +40,6 @@ const configSchema = {
|
|||
readyTimeout: { type: "integer" },
|
||||
keepaliveInterval: { type: "integer" },
|
||||
keepaliveCountMax: { type: "integer" },
|
||||
disableInteractiveAuth: { type: "boolean" },
|
||||
algorithms: {
|
||||
type: "object",
|
||||
properties: {
|
||||
|
|
|
@ -32,14 +32,14 @@ function createAuthMiddleware(config) {
|
|||
// eslint-disable-next-line consistent-return
|
||||
return (req, res, next) => {
|
||||
// Check if username and either password or private key is configured
|
||||
if (config.user.name && (config.user.password || config.user.privatekey)) {
|
||||
if (config.user.name && (config.user.password || config.user.privateKey)) {
|
||||
req.session.sshCredentials = {
|
||||
username: config.user.name
|
||||
}
|
||||
|
||||
// Add credentials based on what's available
|
||||
if (config.user.privatekey) {
|
||||
req.session.sshCredentials.privatekey = config.user.privatekey
|
||||
if (config.user.privateKey) {
|
||||
req.session.sshCredentials.privateKey = config.user.privateKey
|
||||
}
|
||||
if (config.user.password) {
|
||||
req.session.sshCredentials.password = config.user.password
|
||||
|
|
|
@ -25,7 +25,7 @@ class WebSSH2Socket extends EventEmitter {
|
|||
authenticated: false,
|
||||
username: null,
|
||||
password: null,
|
||||
privatekey: null,
|
||||
privateKey: null,
|
||||
keyPassword: null,
|
||||
host: null,
|
||||
port: null,
|
||||
|
@ -117,11 +117,6 @@ class WebSSH2Socket extends EventEmitter {
|
|||
? creds.term
|
||||
: this.config.ssh.term
|
||||
|
||||
// Map the client's privateKey field to our internal privatekey field if present
|
||||
if (creds.privateKey) {
|
||||
creds.privatekey = creds.privateKey
|
||||
}
|
||||
|
||||
this.initializeConnection(creds)
|
||||
} else {
|
||||
debug(`handleAuthenticate: ${this.socket.id}, CREDENTIALS INVALID`)
|
||||
|
@ -139,8 +134,8 @@ class WebSSH2Socket extends EventEmitter {
|
|||
)
|
||||
|
||||
// Add private key from config if available and not provided in creds
|
||||
if (this.config.user.privatekey && !creds.privatekey) {
|
||||
creds.privatekey = this.config.user.privatekey
|
||||
if (this.config.user.privateKey && !creds.privateKey) {
|
||||
creds.privateKey = this.config.user.privateKey
|
||||
}
|
||||
|
||||
this.ssh
|
||||
|
@ -150,7 +145,7 @@ class WebSSH2Socket extends EventEmitter {
|
|||
authenticated: true,
|
||||
username: creds.username,
|
||||
password: creds.password,
|
||||
privatekey: creds.privatekey,
|
||||
privateKey: creds.privateKey,
|
||||
keyPassword: creds.keyPassword,
|
||||
host: creds.host,
|
||||
port: creds.port
|
||||
|
|
|
@ -160,9 +160,9 @@ class SSHConnection extends EventEmitter {
|
|||
}
|
||||
|
||||
// Try private key first if available and useKey is true
|
||||
if (useKey && (creds.privatekey || this.config.user.privatekey)) {
|
||||
if (useKey && (creds.privateKey || this.config.user.privateKey)) {
|
||||
debug("Using private key authentication")
|
||||
const privateKey = creds.privatekey || this.config.user.privatekey
|
||||
const privateKey = creds.privateKey || this.config.user.privateKey
|
||||
if (!this.validatePrivateKey(privateKey)) {
|
||||
throw new SSHConnectionError("Invalid private key format")
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ function getValidatedPort(portInput) {
|
|||
* - port (number)
|
||||
* AND either:
|
||||
* - password (string) OR
|
||||
* - privatekey/privateKey (string)
|
||||
* - privateKey/privateKey (string)
|
||||
*
|
||||
* @param {Object} creds - The credentials object.
|
||||
* @returns {boolean} - Returns true if the credentials are valid, otherwise false.
|
||||
|
@ -104,10 +104,10 @@ function isValidCredentials(creds) {
|
|||
return false
|
||||
}
|
||||
|
||||
// Must have either password or privatekey/privateKey
|
||||
// Must have either password or privateKey/privateKey
|
||||
const hasPassword = typeof creds.password === "string"
|
||||
const hasPrivateKey =
|
||||
typeof creds.privatekey === "string" || typeof creds.privateKey === "string"
|
||||
typeof creds.privateKey === "string" || typeof creds.privateKey === "string"
|
||||
|
||||
return hasPassword || hasPrivateKey
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ describe("SSHConnection", () => {
|
|||
user: {
|
||||
name: null,
|
||||
password: null,
|
||||
privatekey: null
|
||||
privateKey: null
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ MIIEpTestKeyContentHere
|
|||
port: 22,
|
||||
username: "user",
|
||||
password: "pass",
|
||||
privatekey: validPrivateKey
|
||||
privateKey: validPrivateKey
|
||||
}
|
||||
|
||||
return sshConnection.connect(mockCreds).then(() => {
|
||||
|
@ -168,7 +168,7 @@ MIIEpTestKeyContentHere
|
|||
port: 22,
|
||||
username: "user",
|
||||
password: "pass",
|
||||
privatekey: validPrivateKey
|
||||
privateKey: validPrivateKey
|
||||
}
|
||||
|
||||
let authAttempts = 0
|
||||
|
@ -205,7 +205,7 @@ MIIEpTestKeyContentHere
|
|||
host: "localhost",
|
||||
port: 22,
|
||||
username: "user",
|
||||
privatekey: "invalid-key-format"
|
||||
privateKey: "invalid-key-format"
|
||||
}
|
||||
|
||||
return sshConnection.connect(mockCreds).catch((error) => {
|
||||
|
|
|
@ -152,7 +152,7 @@ describe("utils", () => {
|
|||
user: {
|
||||
name: null,
|
||||
password: null,
|
||||
privatekey: null
|
||||
privateKey: null
|
||||
},
|
||||
ssh: {
|
||||
host: null,
|
||||
|
|
Loading…
Reference in a new issue