forked from pytool/ssh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
auth.go
188 lines (166 loc) · 5.07 KB
/
auth.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package ssh
import (
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"strings"
"syscall"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"golang.org/x/crypto/ssh/terminal"
)
//HasAgent reports whether the SSH agent is available
func HasAgent() bool {
authsock, ok := os.LookupEnv("SSH_AUTH_SOCK")
if !ok {
return false
}
if dirent, err := os.Stat(authsock); err != nil {
if os.IsNotExist(err) {
return false
}
if dirent.Mode()&os.ModeSocket == 0 {
return false
}
}
return true
}
// An implementation of ssh.KeyboardInteractiveChallenge that simply sends
// back the password for all questions. The questions are logged.
func passwordKeyboardInteractive(password string) ssh.KeyboardInteractiveChallenge {
return func(user, instruction string, questions []string, echos []bool) ([]string, error) {
// log.Printf("Keyboard interactive challenge: ")
// log.Printf("-- User: %s", user)
// log.Printf("-- Instructions: %s", instruction)
// for i, question := range questions {
// log.Printf("-- Question %d: %s", i+1, question)
// }
// Just send the password back for all questions
answers := make([]string, len(questions))
for i := range answers {
answers[i] = password
}
return answers, nil
}
}
// AuthWithKeyboardPassword Generate a password-auth'd ssh ClientConfig
func AuthWithKeyboardPassword(password string) (ssh.AuthMethod, error) {
return ssh.KeyboardInteractive(passwordKeyboardInteractive(password)), nil
}
// AuthWithPassword Generate a password-auth'd ssh ClientConfig
func AuthWithPassword(password string) (ssh.AuthMethod, error) {
return ssh.Password(password), nil
}
// AuthWithAgent use already authed user
func AuthWithAgent() (ssh.AuthMethod, error) {
sock := os.Getenv("SSH_AUTH_SOCK")
if sock == "" {
// fmt.Println(errors.New("Agent Disabled"))
return nil, errors.New("Agent Disabled")
}
socks, err := net.Dial("unix", sock)
if err != nil {
fmt.Println(err)
return nil, err
}
// 1. 返回Signers函数的结果
agent := agent.NewClient(socks)
signers, err := agent.Signers()
return ssh.PublicKeys(signers...), nil
// 2. 返回Signers函数
// getSigners := agent.NewClient(socks).Signers
// return ssh.PublicKeysCallback(getSigners), nil
// 3.简写方式
// if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
// return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
// }
// return nil
}
// AuthWithPrivateKeys 设置多个 ~/.ssh/id_rsa ,如果加密用passphrase尝试
func AuthWithPrivateKeys(keyFiles []string, passphrase string) (ssh.AuthMethod, error) {
var signers []ssh.Signer
for _, key := range keyFiles {
pemBytes, err := ioutil.ReadFile(key)
if err != nil {
println(err.Error())
// return
}
signer, err := ssh.ParsePrivateKey([]byte(pemBytes))
if err != nil {
if strings.Contains(err.Error(), "cannot decode encrypted private keys") {
if signer, err = ssh.ParsePrivateKeyWithPassphrase(pemBytes, []byte(passphrase)); err != nil {
continue
}
}
// println(err.Error())
}
signers = append(signers, signer)
}
if signers == nil {
return nil, errors.New("WithPrivateKeys: no keyfiles input")
}
return ssh.PublicKeys(signers...), nil
}
// AuthWithPrivateKey 自动监测是否带有密码
func AuthWithPrivateKey(keyfile string, passphrase string) (ssh.AuthMethod, error) {
pemBytes, err := ioutil.ReadFile(keyfile)
if err != nil {
println(err.Error())
return nil, err
}
var signer ssh.Signer
signer, err = ssh.ParsePrivateKey(pemBytes)
if err != nil {
if strings.Contains(err.Error(), "cannot decode encrypted private keys") {
signer, err = ssh.ParsePrivateKeyWithPassphrase(pemBytes, []byte(passphrase))
if err == nil {
return ssh.PublicKeys(signer), nil
}
}
return nil, err
}
return ssh.PublicKeys(signer), nil
}
// AuthWithPrivateKeyString 直接通过字符串
func AuthWithPrivateKeyString(key string, password string) (ssh.AuthMethod, error) {
var signer ssh.Signer
var err error
if password == "" {
signer, err = ssh.ParsePrivateKey([]byte(key))
} else {
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(key), []byte(password))
}
if err != nil {
println(err.Error())
return nil, err
}
return ssh.PublicKeys(signer), nil
}
// AuthWithPrivateKeyTerminal 通过终端读取带密码的 PublicKey
func AuthWithPrivateKeyTerminal(keyfile string) (ssh.AuthMethod, error) {
pemBytes, err := ioutil.ReadFile(keyfile)
if err != nil {
println(err.Error())
return nil, err
}
var signer ssh.Signer
signer, err = ssh.ParsePrivateKey(pemBytes)
if err != nil {
if strings.Contains(err.Error(), "cannot decode encrypted private keys") {
fmt.Fprintf(os.Stderr, "This SSH key is encrypted. Please enter passphrase for key '%s':", keyfile)
passphrase, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
// println(err.Error())
return nil, err
}
fmt.Fprintln(os.Stderr)
if signer, err = ssh.ParsePrivateKeyWithPassphrase(pemBytes, []byte(passphrase)); err == nil {
return ssh.PublicKeys(signer), nil
}
}
return nil, err
}
return ssh.PublicKeys(signer), nil
}