1
1
mirror of https://github.com/Eugeny/tabby.git synced 2024-11-28 05:36:31 +03:00

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

This commit is contained in:
Eugene Pankov 2020-07-29 19:18:57 +02:00
parent 34752ed69e
commit da21895e40
5 changed files with 81 additions and 12 deletions

View File

@ -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[]}
}

View File

@ -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

View File

@ -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]) {

View File

@ -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(),
{

View File

@ -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)