@@ -25,8 +25,9 @@ const DefaultUsername = "git"
25
25
// configuration needed to establish an ssh connection.
26
26
type AuthMethod interface {
27
27
transport.AuthMethod
28
- clientConfig () * ssh.ClientConfig
29
- hostKeyCallback () (ssh.HostKeyCallback , error )
28
+ // ClientConfig should return a valid ssh.ClientConfig to be used to create
29
+ // a connection to the SSH server.
30
+ ClientConfig () (* ssh.ClientConfig , error )
30
31
}
31
32
32
33
// The names of the AuthMethod implementations. To be returned by the
@@ -45,7 +46,7 @@ const (
45
46
type KeyboardInteractive struct {
46
47
User string
47
48
Challenge ssh.KeyboardInteractiveChallenge
48
- baseAuthMethod
49
+ HostKeyCallbackHelper
49
50
}
50
51
51
52
func (a * KeyboardInteractive ) Name () string {
@@ -56,18 +57,20 @@ func (a *KeyboardInteractive) String() string {
56
57
return fmt .Sprintf ("user: %s, name: %s" , a .User , a .Name ())
57
58
}
58
59
59
- func (a * KeyboardInteractive ) clientConfig () * ssh.ClientConfig {
60
- return & ssh.ClientConfig {
60
+ func (a * KeyboardInteractive ) ClientConfig () ( * ssh.ClientConfig , error ) {
61
+ return a . SetHostKeyCallback ( & ssh.ClientConfig {
61
62
User : a .User ,
62
- Auth : []ssh.AuthMethod {ssh .KeyboardInteractiveChallenge (a .Challenge )},
63
- }
63
+ Auth : []ssh.AuthMethod {
64
+ ssh .KeyboardInteractiveChallenge (a .Challenge ),
65
+ },
66
+ })
64
67
}
65
68
66
69
// Password implements AuthMethod by using the given password.
67
70
type Password struct {
68
- User string
69
- Pass string
70
- baseAuthMethod
71
+ User string
72
+ Password string
73
+ HostKeyCallbackHelper
71
74
}
72
75
73
76
func (a * Password ) Name () string {
@@ -78,19 +81,19 @@ func (a *Password) String() string {
78
81
return fmt .Sprintf ("user: %s, name: %s" , a .User , a .Name ())
79
82
}
80
83
81
- func (a * Password ) clientConfig () * ssh.ClientConfig {
82
- return & ssh.ClientConfig {
84
+ func (a * Password ) ClientConfig () ( * ssh.ClientConfig , error ) {
85
+ return a . SetHostKeyCallback ( & ssh.ClientConfig {
83
86
User : a .User ,
84
- Auth : []ssh.AuthMethod {ssh .Password (a .Pass )},
85
- }
87
+ Auth : []ssh.AuthMethod {ssh .Password (a .Password )},
88
+ })
86
89
}
87
90
88
91
// PasswordCallback implements AuthMethod by using a callback
89
92
// to fetch the password.
90
93
type PasswordCallback struct {
91
94
User string
92
95
Callback func () (pass string , err error )
93
- baseAuthMethod
96
+ HostKeyCallbackHelper
94
97
}
95
98
96
99
func (a * PasswordCallback ) Name () string {
@@ -101,25 +104,25 @@ func (a *PasswordCallback) String() string {
101
104
return fmt .Sprintf ("user: %s, name: %s" , a .User , a .Name ())
102
105
}
103
106
104
- func (a * PasswordCallback ) clientConfig () * ssh.ClientConfig {
105
- return & ssh.ClientConfig {
107
+ func (a * PasswordCallback ) ClientConfig () ( * ssh.ClientConfig , error ) {
108
+ return a . SetHostKeyCallback ( & ssh.ClientConfig {
106
109
User : a .User ,
107
110
Auth : []ssh.AuthMethod {ssh .PasswordCallback (a .Callback )},
108
- }
111
+ })
109
112
}
110
113
111
114
// PublicKeys implements AuthMethod by using the given key pairs.
112
115
type PublicKeys struct {
113
116
User string
114
117
Signer ssh.Signer
115
- baseAuthMethod
118
+ HostKeyCallbackHelper
116
119
}
117
120
118
121
// NewPublicKeys returns a PublicKeys from a PEM encoded private key. An
119
122
// encryption password should be given if the pemBytes contains a password
120
123
// encrypted PEM block otherwise password should be empty. It supports RSA
121
124
// (PKCS#1), DSA (OpenSSL), and ECDSA private keys.
122
- func NewPublicKeys (user string , pemBytes []byte , password string ) (AuthMethod , error ) {
125
+ func NewPublicKeys (user string , pemBytes []byte , password string ) (* PublicKeys , error ) {
123
126
block , _ := pem .Decode (pemBytes )
124
127
if x509 .IsEncryptedPEMBlock (block ) {
125
128
key , err := x509 .DecryptPEMBlock (block , []byte (password ))
@@ -142,7 +145,7 @@ func NewPublicKeys(user string, pemBytes []byte, password string) (AuthMethod, e
142
145
// NewPublicKeysFromFile returns a PublicKeys from a file containing a PEM
143
146
// encoded private key. An encryption password should be given if the pemBytes
144
147
// contains a password encrypted PEM block otherwise password should be empty.
145
- func NewPublicKeysFromFile (user , pemFile , password string ) (AuthMethod , error ) {
148
+ func NewPublicKeysFromFile (user , pemFile , password string ) (* PublicKeys , error ) {
146
149
bytes , err := ioutil .ReadFile (pemFile )
147
150
if err != nil {
148
151
return nil , err
@@ -159,11 +162,11 @@ func (a *PublicKeys) String() string {
159
162
return fmt .Sprintf ("user: %s, name: %s" , a .User , a .Name ())
160
163
}
161
164
162
- func (a * PublicKeys ) clientConfig () * ssh.ClientConfig {
163
- return & ssh.ClientConfig {
165
+ func (a * PublicKeys ) ClientConfig () ( * ssh.ClientConfig , error ) {
166
+ return a . SetHostKeyCallback ( & ssh.ClientConfig {
164
167
User : a .User ,
165
168
Auth : []ssh.AuthMethod {ssh .PublicKeys (a .Signer )},
166
- }
169
+ })
167
170
}
168
171
169
172
func username () (string , error ) {
@@ -173,9 +176,11 @@ func username() (string, error) {
173
176
} else {
174
177
username = os .Getenv ("USER" )
175
178
}
179
+
176
180
if username == "" {
177
181
return "" , errors .New ("failed to get username" )
178
182
}
183
+
179
184
return username , nil
180
185
}
181
186
@@ -184,13 +189,13 @@ func username() (string, error) {
184
189
type PublicKeysCallback struct {
185
190
User string
186
191
Callback func () (signers []ssh.Signer , err error )
187
- baseAuthMethod
192
+ HostKeyCallbackHelper
188
193
}
189
194
190
195
// NewSSHAgentAuth returns a PublicKeysCallback based on a SSH agent, it opens
191
196
// a pipe with the SSH agent and uses the pipe as the implementer of the public
192
197
// key callback function.
193
- func NewSSHAgentAuth (u string ) (AuthMethod , error ) {
198
+ func NewSSHAgentAuth (u string ) (* PublicKeysCallback , error ) {
194
199
var err error
195
200
if u == "" {
196
201
u , err = username ()
@@ -218,11 +223,11 @@ func (a *PublicKeysCallback) String() string {
218
223
return fmt .Sprintf ("user: %s, name: %s" , a .User , a .Name ())
219
224
}
220
225
221
- func (a * PublicKeysCallback ) clientConfig () * ssh.ClientConfig {
222
- return & ssh.ClientConfig {
226
+ func (a * PublicKeysCallback ) ClientConfig () ( * ssh.ClientConfig , error ) {
227
+ return a . SetHostKeyCallback ( & ssh.ClientConfig {
223
228
User : a .User ,
224
229
Auth : []ssh.AuthMethod {ssh .PublicKeysCallback (a .Callback )},
225
- }
230
+ })
226
231
}
227
232
228
233
// NewKnownHostsCallback returns ssh.HostKeyCallback based on a file based on a
@@ -287,17 +292,26 @@ func filterKnownHostsFiles(files ...string) ([]string, error) {
287
292
return out , nil
288
293
}
289
294
290
- type baseAuthMethod struct {
295
+ // HostKeyCallbackHelper is a helper that provides common functionality to
296
+ // configure HostKeyCallback into a ssh.ClientConfig.
297
+ type HostKeyCallbackHelper struct {
291
298
// HostKeyCallback is the function type used for verifying server keys.
292
- // If nil default callback will be create using NewKnownHostsHostKeyCallback
299
+ // If nil default callback will be create using NewKnownHostsCallback
293
300
// without argument.
294
301
HostKeyCallback ssh.HostKeyCallback
295
302
}
296
303
297
- func (m * baseAuthMethod ) hostKeyCallback () (ssh.HostKeyCallback , error ) {
304
+ // SetHostKeyCallback sets the field HostKeyCallback in the given cfg. If
305
+ // HostKeyCallback is empty a default callback is created using
306
+ // NewKnownHostsCallback.
307
+ func (m * HostKeyCallbackHelper ) SetHostKeyCallback (cfg * ssh.ClientConfig ) (* ssh.ClientConfig , error ) {
308
+ var err error
298
309
if m .HostKeyCallback == nil {
299
- return NewKnownHostsCallback ()
310
+ if m .HostKeyCallback , err = NewKnownHostsCallback (); err != nil {
311
+ return cfg , err
312
+ }
300
313
}
301
314
302
- return m .HostKeyCallback , nil
315
+ cfg .HostKeyCallback = m .HostKeyCallback
316
+ return cfg , nil
303
317
}
0 commit comments