diff --git a/extensions/SSHSessionBackend/src/SSHPty.ts b/extensions/SSHSessionBackend/src/SSHPty.ts index dc9624f5..83dc91ab 100644 --- a/extensions/SSHSessionBackend/src/SSHPty.ts +++ b/extensions/SSHSessionBackend/src/SSHPty.ts @@ -26,6 +26,7 @@ export interface PtyOptions { username: string; privateKeyFilenames?: string[]; tryPasswordAuth: boolean; + agentSocketPath?: string; } enum PtyState { @@ -48,6 +49,7 @@ export class SSHPty implements Pty { #password: string = ""; #ptyOptions: PtyOptions = null; + #tryAgentAuth = false; #verifyCallback: ssh2.VerifyCallback = null; #permittedDataSize = 0; @@ -154,11 +156,14 @@ export class SSHPty implements Pty { }); }); + this.#tryAgentAuth = options.agentSocketPath !== undefined; + this.#sshConnection.connect({ host: options.host, port: options.port, username: options.username, tryKeyboard: true, + agent: options.agentSocketPath, authHandler: ( methodsLeft: ssh2.AuthenticationType[], partialSuccess: boolean, @@ -359,6 +364,12 @@ export class SSHPty implements Pty { partialSuccess: boolean, callback: ssh2.NextAuthHandler): void { + if (this.#tryAgentAuth) { + this.#tryAgentAuth = false; + callback({type: "agent", agent: this.#ptyOptions.agentSocketPath, username: this.#ptyOptions.username}); + return; + } + while (this.#remainingPrivateKeyFilenames.length !== 0) { const keyFilename = this.#remainingPrivateKeyFilenames.pop(); if (this.#handlePrivateKeyAuth(keyFilename, callback)) { @@ -368,6 +379,7 @@ export class SSHPty implements Pty { if (this.#tryPasswordAuth) { this.#startPasswordInput(callback); + return; } callback(false); diff --git a/extensions/SSHSessionBackend/src/SSHSessionBackendExtension.ts b/extensions/SSHSessionBackend/src/SSHSessionBackendExtension.ts index 4a18f4d7..b6bdc9c3 100644 --- a/extensions/SSHSessionBackend/src/SSHSessionBackendExtension.ts +++ b/extensions/SSHSessionBackend/src/SSHSessionBackendExtension.ts @@ -16,7 +16,8 @@ import { PtyOptions, SSHPty } from "./SSHPty"; enum AuthenticationMethod { DEFAULT_KEYS_PASSWORD, PASSWORD_ONLY, - KEY_FILE_ONLY + KEY_FILE_ONLY, + SSH_AGENT_ONLY, }; // Note: This is duplicated in SSHSessionEditorExtension.ts. @@ -63,12 +64,15 @@ class SSHBackend implements SessionBackend { tryPasswordAuth = true; break; + case AuthenticationMethod.KEY_FILE_ONLY: + privateKeyFilenames.push(sessionConfig.keyFilePath); + break; + case AuthenticationMethod.PASSWORD_ONLY: tryPasswordAuth = true; break; - case AuthenticationMethod.KEY_FILE_ONLY: - privateKeyFilenames.push(sessionConfig.keyFilePath); + default: break; } @@ -82,11 +86,26 @@ class SSHBackend implements SessionBackend { username: username, privateKeyFilenames, tryPasswordAuth, + agentSocketPath: this.#createAgentSocketPath(sessionConfig), }; return new SSHPty(this._log, options); } + #createAgentSocketPath(sessionConfig: SSHSessionConfiguration): string { + const needAgent = sessionConfig.authenicationMethod === AuthenticationMethod.DEFAULT_KEYS_PASSWORD || + sessionConfig.authenicationMethod === AuthenticationMethod.SSH_AGENT_ONLY; + if (! needAgent) { + return undefined; + } + + if (process.platform === "win32") { + return undefined; + } else { + return process.env.SSH_AUTH_SOCK; + } + } + #createEnv(sessionOptions: CreateSessionOptions): EnvironmentMap { const ptyEnv: EnvironmentMap = {}; const processEnv = process.env; diff --git a/extensions/SSHSessionEditor/src/SSHSessionEditorExtension.ts b/extensions/SSHSessionEditor/src/SSHSessionEditorExtension.ts index b0f7ba16..88420bde 100644 --- a/extensions/SSHSessionEditor/src/SSHSessionEditorExtension.ts +++ b/extensions/SSHSessionEditor/src/SSHSessionEditorExtension.ts @@ -14,10 +14,16 @@ let log: Logger = null; enum AuthenticationMethod { DEFAULT_KEYS_PASSWORD, PASSWORD_ONLY, - KEY_FILE_ONLY + KEY_FILE_ONLY, + SSH_AGENT_ONLY, }; -const AUTHENTICATION_METHOD_LABELS = ["Default OpenSSH keys, Password", "Password only", "Key file only"]; +const AUTHENTICATION_METHOD_LABELS = [ + "SSH Agent, Default OpenSSH keys, Password", + "Password only", + "Key file only", + "SSH Agent only" +]; // Note: This is duplicated in SSHSessionBackendExtension.ts. interface SSHSessionConfiguration extends SessionConfiguration {