/
login.go
130 lines (115 loc) · 3.86 KB
/
login.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package cmd
import (
"fmt"
"net"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"golang.org/x/crypto/ssh/terminal"
)
var loginCmd = &cobra.Command{
Use: "login",
Short: "Log into a Lagoon instance",
Aliases: []string{"l"},
Run: func(cmd *cobra.Command, args []string) {
validateToken(lagoonCLIConfig.Current) // get a new token if the current one is invalid
fmt.Println("Token fetched and saved.")
},
}
func publicKey(path string, skipAgent bool) (ssh.AuthMethod, func() error) {
noopCloseFunc := func() error { return nil }
if !skipAgent {
// Connect to SSH agent to ask for unencrypted private keys
if sshAgentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
sshAgent := agent.NewClient(sshAgentConn)
keys, _ := sshAgent.List()
if len(keys) > 0 {
// There are key(s) in the agent
//defer sshAgentConn.Close()
return ssh.PublicKeysCallback(sshAgent.Signers), sshAgentConn.Close
}
}
}
key, err := os.ReadFile(path)
handleError(err)
// Try to look for an unencrypted private key
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
fmt.Printf("Enter passphrase for %s:", path)
bytePassword, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
fmt.Println("Error was:", err.Error())
fmt.Println("Lagoon CLI could not decode private key, you will need to add your private key to your ssh-agent.")
os.Exit(1)
}
fmt.Println()
signer, err = ssh.ParsePrivateKeyWithPassphrase(key, bytePassword)
if err != nil {
fmt.Println("Error was:", err.Error())
fmt.Println("Lagoon CLI could not decode private key, you will need to add your private key to your ssh-agent.")
os.Exit(1)
}
return ssh.PublicKeys(signer), noopCloseFunc
}
// return unencrypted private key
return ssh.PublicKeys(signer), noopCloseFunc
}
func loginToken() error {
out, err := retrieveTokenViaSsh()
if err != nil {
return err
}
lc := lagoonCLIConfig.Lagoons[lagoonCLIConfig.Current]
lc.Token = out
lagoonCLIConfig.Lagoons[lagoonCLIConfig.Current] = lc
if err = writeLagoonConfig(&lagoonCLIConfig, filepath.Join(configFilePath, configName+configExtension)); err != nil {
return fmt.Errorf("couldn't write config: %v", err)
}
if err = versionCheck(lagoonCLIConfig.Current); err != nil {
return fmt.Errorf("couldn't check version: %v", err)
}
return nil
}
func retrieveTokenViaSsh() (string, error) {
skipAgent := false
privateKey := fmt.Sprintf("%s/.ssh/id_rsa", userPath)
// if the user has a key defined in their lagoon cli config, use it
if lagoonCLIConfig.Lagoons[lagoonCLIConfig.Current].SSHKey != "" {
privateKey = lagoonCLIConfig.Lagoons[lagoonCLIConfig.Current].SSHKey
skipAgent = true
}
// otherwise check if one has been provided by the override flag
if cmdSSHKey != "" {
privateKey = cmdSSHKey
skipAgent = true
}
authMethod, closeSSHAgent := publicKey(privateKey, skipAgent)
config := &ssh.ClientConfig{
User: "lagoon",
Auth: []ssh.AuthMethod{
authMethod,
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
defer closeSSHAgent()
sshHost := fmt.Sprintf("%s:%s",
lagoonCLIConfig.Lagoons[lagoonCLIConfig.Current].HostName,
lagoonCLIConfig.Lagoons[lagoonCLIConfig.Current].Port)
conn, err := ssh.Dial("tcp", sshHost, config)
if err != nil {
return "", fmt.Errorf("unable to authenticate or connect to host %s\nthere may be an issue determining which ssh-key to use, or there may be an issue establishing a connection to the host\nthe error returned was: %v", sshHost, err)
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
return "", fmt.Errorf("unable to establish ssh session, error from attempt is: %v", err)
}
out, err := session.CombinedOutput("token")
if err != nil {
return "", fmt.Errorf("unable to get token: %v", err)
}
return strings.TrimSpace(string(out)), err
}