refactor: move logic for wave and config options

The logic for making decisions between details made available from wave
and details made available from ssh_config was spread out. This change
condenses it into one function for gathering those details and one for
picking between them.

It also adds a few new keywords but the logic for those hasn't been
implemented yet.
This commit is contained in:
Sylvia Crowe 2024-02-09 22:44:55 -08:00
parent b788a5e4af
commit 618a08fe54

View File

@ -454,55 +454,134 @@ func createHostKeyCallback(opts *sstore.SSHOpts) (ssh.HostKeyCallback, error) {
} }
func ConnectToClient(opts *sstore.SSHOpts) (*ssh.Client, error) { func ConnectToClient(opts *sstore.SSHOpts) (*ssh.Client, error) {
ssh_config.ReloadConfigs() sshConfigKeywords, err := findSshConfigKeywords(opts.SSHHost)
configIdentityFiles := ssh_config.GetAll(opts.SSHHost, "IdentityFile") if err != nil {
identityFiles := []string{opts.SSHIdentity} return nil, err
identityFiles = append(identityFiles, configIdentityFiles...) }
sshKeywords, err := combineSshKeywords(opts, sshConfigKeywords)
if err != nil {
return nil, err
}
publicKeyCallback := ssh.PublicKeysCallback(createPublicKeyCallback(&sshKeywords.IdentityFile, opts.SSHPassword))
var authMethods []ssh.AuthMethod
authMethods = append(authMethods, ssh.RetryableAuthMethod(publicKeyCallback, len(sshKeywords.IdentityFile)))
authMethods = append(authMethods, ssh.RetryableAuthMethod(ssh.KeyboardInteractive(createCombinedKbdInteractiveChallenge(opts.SSHPassword)), 2))
authMethods = append(authMethods, ssh.RetryableAuthMethod(ssh.PasswordCallback(createCombinedPasswordCallbackPrompt(opts.SSHPassword)), 2))
hostKeyCallback, err := createHostKeyCallback(opts) hostKeyCallback, err := createHostKeyCallback(opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
publicKeyCallback := ssh.PublicKeysCallback(createPublicKeyCallback(&identityFiles, opts.SSHPassword))
var authMethods []ssh.AuthMethod
authMethods = append(authMethods, ssh.RetryableAuthMethod(publicKeyCallback, len(identityFiles)))
authMethods = append(authMethods, ssh.RetryableAuthMethod(ssh.KeyboardInteractive(createCombinedKbdInteractiveChallenge(opts.SSHPassword)), 2))
authMethods = append(authMethods, ssh.RetryableAuthMethod(ssh.PasswordCallback(createCombinedPasswordCallbackPrompt(opts.SSHPassword)), 2))
configUser, _ := ssh_config.GetStrict(opts.SSHHost, "User") clientConfig := &ssh.ClientConfig{
configHostName, _ := ssh_config.GetStrict(opts.SSHHost, "HostName") User: sshKeywords.User,
configPort, _ := ssh_config.GetStrict(opts.SSHHost, "Port") Auth: authMethods,
var username string HostKeyCallback: hostKeyCallback,
}
networkAddr := sshKeywords.HostName + ":" + sshKeywords.Port
return ssh.Dial("tcp", networkAddr, clientConfig)
}
type SshKeywords struct {
User string
HostName string
Port string
IdentityFile []string
BatchMode bool
PasswordAuthentication bool
KbdInteractiveAuthentication bool
PreferredAuthentications []string
}
func combineSshKeywords(opts *sstore.SSHOpts, configKeywords *SshKeywords) (*SshKeywords, error) {
sshKeywords := &SshKeywords{}
if opts.SSHUser != "" { if opts.SSHUser != "" {
username = opts.SSHUser sshKeywords.User = opts.SSHUser
} else if configUser != "" { } else if configKeywords.User != "" {
username = configUser sshKeywords.User = configKeywords.User
} else { } else {
user, err := user.Current() user, err := user.Current()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get user for ssh: %+v", err) return nil, fmt.Errorf("failed to get user for ssh: %+v", err)
} }
username = user.Username sshKeywords.User = user.Username
} }
var hostName string
if configHostName != "" { // we have to check the host value because of the weird way
hostName = configHostName // we store the pattern as the hostname for imported remotes
if configKeywords.HostName != "" {
sshKeywords.HostName = configKeywords.HostName
} else { } else {
hostName = opts.SSHHost sshKeywords.HostName = opts.SSHHost
} }
clientConfig := &ssh.ClientConfig{
User: username,
Auth: authMethods,
HostKeyCallback: hostKeyCallback,
}
var port string
if opts.SSHPort != 0 && opts.SSHPort != 22 { if opts.SSHPort != 0 && opts.SSHPort != 22 {
port = strconv.Itoa(opts.SSHPort) sshKeywords.Port = strconv.Itoa(opts.SSHPort)
} else if configPort != "" && configPort != "22" { } else if configKeywords.Port != "" && configKeywords.Port != "22" {
port = configPort sshKeywords.Port = configKeywords.Port
} else { } else {
port = "22" sshKeywords.Port = "22"
} }
networkAddr := hostName + ":" + port
return ssh.Dial("tcp", networkAddr, clientConfig) sshKeywords.IdentityFile = []string{opts.SSHIdentity}
sshKeywords.IdentityFile = append(sshKeywords.IdentityFile, configKeywords.IdentityFile...)
// these are not officially supported in the waveterm frontend but can be configured
// in ssh config files
sshKeywords.BatchMode = configKeywords.BatchMode
sshKeywords.PasswordAuthentication = configKeywords.PasswordAuthentication
sshKeywords.KbdInteractiveAuthentication = configKeywords.KbdInteractiveAuthentication
sshKeywords.PreferredAuthentications = configKeywords.PreferredAuthentications
return sshKeywords, nil
}
func findSshConfigKeywords(hostPattern string) (*SshKeywords, error) {
ssh_config.ReloadConfigs()
sshKeywords := &SshKeywords{}
var err error
sshKeywords.User, err = ssh_config.GetStrict(hostPattern, "User")
if err != nil {
return nil, err
}
sshKeywords.HostName, err = ssh_config.GetStrict(hostPattern, "HostName")
if err != nil {
return nil, err
}
sshKeywords.Port, err = ssh_config.GetStrict(hostPattern, "Port")
if err != nil {
return nil, err
}
sshKeywords.IdentityFile = ssh_config.GetAll(hostPattern, "IdentityFile")
batchModeRaw, err := ssh_config.GetStrict(hostPattern, "BatchMode")
if err != nil {
return nil, err
}
sshKeywords.BatchMode = (strings.ToLower(batchModeRaw) == "yes")
passwordAuthenticationRaw, err := ssh_config.GetStrict(hostPattern, "PasswordAuthentication")
if err != nil {
return nil, err
}
sshKeywords.PasswordAuthentication = (strings.ToLower(passwordAuthenticationRaw) == "yes")
kbdInteractiveAuthenticationRaw, err := ssh_config.GetStrict(hostPattern, "KbdInteractiveAuthentication")
if err != nil {
return nil, err
}
sshKeywords.KbdInteractiveAuthentication = (strings.ToLower(kbdInteractiveAuthenticationRaw) == "yes")
// these are case sensitive in openssh so they are here too
sshKeywords.PreferredAuthentications = ssh_config.GetAll(hostPattern, "PreferredAuthentications")
return sshKeywords, nil
} }