Преглед изворни кода

more explicit SSH auth options and agent forwarding - fixes #2284, fixes #2511, fixes #2717, fixes #2184

Eugene Pankov пре 5 година
родитељ
комит
da21895e40

+ 1 - 1
terminus-ssh/src/api.ts

@@ -24,6 +24,7 @@ export interface SSHConnection {
     host: string
     port: number
     user: string
+    auth?: null|'password'|'publicKey'|'agent'|'keyboardInteractive'
     password?: string
     privateKey?: string
     group: string | null
@@ -36,7 +37,6 @@ export interface SSHConnection {
     skipBanner?: boolean
     disableDynamicTitle?: boolean
     jumpHost?: string
-    agentForward?: boolean
 
     algorithms?: {[t: string]: string[]}
 }

+ 29 - 6
terminus-ssh/src/components/editConnectionModal.component.pug

@@ -43,6 +43,34 @@
                     )
 
                 .form-line
+                    .header
+                        .title Authentication
+                .btn-group.w-100(
+                    [(ngModel)]='connection.auth',
+                    ngbRadioGroup
+                )
+                    label.btn.btn-outline-secondary(ngbButtonLabel)
+                        input(type='radio', ngbButton, [value]='null')
+                        i.far.fa-lightbulb
+                        .m-0 Auto
+                    label.btn.btn-outline-secondary(ngbButtonLabel)
+                        input(type='radio', ngbButton, [value]='"password"')
+                        i.fas.fa-font
+                        .m-0 Password
+                    label.btn.btn-outline-secondary(ngbButtonLabel)
+                        input(type='radio', ngbButton, [value]='"publicKey"')
+                        i.fas.fa-key
+                        .m-0 Key
+                    label.btn.btn-outline-secondary(ngbButtonLabel)
+                        input(type='radio', ngbButton, [value]='"agent"')
+                        i.fas.fa-user-secret
+                        .m-0 Agent
+                    label.btn.btn-outline-secondary(ngbButtonLabel)
+                        input(type='radio', ngbButton, [value]='"keyboardInteractive"')
+                        i.far.fa-keyboard
+                        .m-0 Interactive
+
+                .form-line(*ngIf='!connection.auth || connection.auth === "password"')
                     .header
                         .title Password
                         .description(*ngIf='!hasSavedPassword') Save a password in the keychain
@@ -54,7 +82,7 @@
                         i.fas.fa-trash-alt
                         span Forget
 
-                .form-line
+                .form-line(*ngIf='!connection.auth || connection.auth === "publicKey"')
                     .header
                         .title Private key
                         .description Path to the private key file
@@ -83,11 +111,6 @@
                         .title X11 forwarding
                     toggle([(ngModel)]='connection.x11')
 
-                .form-line
-                    .header
-                        .title Allow Agent Forwarding
-                    toggle([(ngModel)]='connection.agentForward')
-
                 .form-line
                     .header
                         .title Tab color

+ 1 - 0
terminus-ssh/src/components/editConnectionModal.component.ts

@@ -49,6 +49,7 @@ export class EditConnectionModalComponent {
         this.hasSavedPassword = !!await this.passwordStorage.loadPassword(this.connection)
         this.connection.algorithms = this.connection.algorithms || {}
         this.connection.scripts = this.connection.scripts || []
+        this.connection.auth = this.connection.auth || null
 
         for (const k of Object.values(SSHAlgorithmType)) {
             if (!this.connection.algorithms[k]) {

+ 3 - 0
terminus-ssh/src/components/sshTab.component.ts

@@ -160,6 +160,9 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
     }
 
     async canClose (): Promise<boolean> {
+        if (!this.session?.open) {
+            return true
+        }
         return (await this.electron.showMessageBox(
             this.hostApp.getWindow(),
             {

+ 47 - 5
terminus-ssh/src/services/ssh.service.ts

@@ -165,8 +165,13 @@ export class SSHService {
                     const modal = this.ngbModal.open(PromptModalComponent)
                     modal.componentInstance.prompt = prompt.prompt
                     modal.componentInstance.password = !prompt.echo
-                    const result = await modal.result
-                    results.push(result ? result.value : '')
+
+                    try {
+                        const result = await modal.result
+                        results.push(result ? result.value : '')
+                    } catch {
+                        results.push('')
+                    }
                 }
                 finish(results)
             }))
@@ -194,6 +199,29 @@ export class SSHService {
                 agent = process.env.SSH_AUTH_SOCK as string
             }
 
+            const authMethodsLeft = ['none']
+            if (!session.connection.auth || session.connection.auth === 'password') {
+                authMethodsLeft.push('password')
+            }
+            if (!session.connection.auth || session.connection.auth === 'publicKey') {
+                if (!privateKey) {
+                    log('\r\nPrivate key auth selected, but no key is loaded\r\n')
+                } else {
+                    authMethodsLeft.push('publickey')
+                }
+            }
+            if (!session.connection.auth || session.connection.auth === 'agent') {
+                if (!agent) {
+                    log('\r\nAgent auth selected, but no running agent is detected\r\n')
+                } else {
+                    authMethodsLeft.push('agent')
+                }
+            }
+            if (!session.connection.auth || session.connection.auth === 'keyboardInteractive') {
+                authMethodsLeft.push('keyboard-interactive')
+            }
+            authMethodsLeft.push('hostbased')
+
             try {
                 ssh.connect({
                     host: session.connection.host,
@@ -202,8 +230,8 @@ export class SSHService {
                     password: session.connection.privateKey ? undefined : '',
                     privateKey: privateKey || undefined,
                     tryKeyboard: true,
-                    agent: session.connection.agentForward && agent || undefined,
-                    agentForward: session.connection.agentForward && !!agent,
+                    agent: agent || undefined,
+                    agentForward: (!session.connection.auth || session.connection.auth === 'agent') && !!agent,
                     keepaliveInterval: session.connection.keepaliveInterval,
                     keepaliveCountMax: session.connection.keepaliveCountMax,
                     readyTimeout: session.connection.readyTimeout,
@@ -215,7 +243,21 @@ export class SSHService {
                     hostHash: 'sha256' as any,
                     algorithms: session.connection.algorithms,
                     sock: session.jumpStream,
-                })
+                    authHandler: methodsLeft => {
+                        while (true) {
+                            let method = authMethodsLeft.shift()
+                            if (!method) {
+                                return false
+                            }
+                            if (methodsLeft && !methodsLeft.includes(method) && method !== 'agent') {
+                                // Agent can still be used even if not in methodsLeft
+                                this.logger.info('Server does not support auth method', method)
+                                continue
+                            }
+                            return method
+                        }
+                    },
+                } as any)
             } catch (e) {
                 this.toastr.error(e.message)
                 reject(e)