8000 plumbing: transport, Reintroduce SetHostKeyCallback. Fix #1514 · go-git/go-git@beedd6b · GitHub
[go: up one dir, main page]

Skip to content

Commit beedd6b

Browse files
committed
plumbing: transport, Reintroduce SetHostKeyCallback. Fix #1514
The PR #1482 renamed SetHostKeyCallback to SetHostKeyCallbackAndAlgorithms, due to the change in behaviour. For keeping backwards compatibility within existing v5, a new SetHostKeyCallback is being introduced that simply calls back to SetHostKeyCallbackAndAlgorithms. Some tests were introduced to enforce expected behaviour. Signed-off-by: Paulo Gomes <pjbgf@linux.com>
1 parent 763ce2e commit beedd6b

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

plumbing/transport/ssh/auth_method.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,10 @@ func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) {
231231
// /etc/ssh/ssh_known_hosts
232232
func NewKnownHostsCallback(files ...string) (ssh.HostKeyCallback, error) {
233233
kh, err := NewKnownHostsDb(files...)
234-
return kh.HostKeyCallback(), err
234+
if err != nil {
235+
return nil, err
236+
}
237+
return kh.HostKeyCallback(), nil
235238
}
236239

237240
// NewKnownHostsDb returns knownhosts.HostKeyDB based on a file based on a
@@ -311,13 +314,40 @@ type HostKeyCallbackHelper struct {
311314
// HostKeyAlgorithms is a list of supported host key algorithms that will
312315
// be used for host key verification.
313316
HostKeyAlgorithms []string
317+
318+
// fallback allows for injecting the fallback call, which is called
319+
// when a HostKeyCallback is not set.
320+
fallback func(files ...string) (ssh.HostKeyCallback, error)
314321
}
315322

316323
// SetHostKeyCallbackAndAlgorithms sets the field HostKeyCallback and HostKeyAlgorithms in the given cfg.
317324
// If the host key callback or algorithms is empty it is left empty. It will be handled by the dial method,
318325
// falling back to knownhosts.
319326
func (m *HostKeyCallbackHelper) SetHostKeyCallbackAndAlgorithms(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) {
327+
if cfg == nil {
328+
cfg = &ssh.ClientConfig{}
329+
}
330+
331+
if m.HostKeyCallback == nil {
332+
if m.fallback == nil {
333+
m.fallback = NewKnownHostsCallback
334+
}
335+
336+
hkcb, err := m.fallback()
337+
if err != nil {
338+
return nil, fmt.Errorf("cannot create known hosts callback: %w", err)
339+
}
340+
341+
cfg.HostKeyCallback = hkcb
342+
cfg.HostKeyAlgorithms = m.HostKeyAlgorithms
343+
return cfg, err
344+
}
345+
320346
cfg.HostKeyCallback = m.HostKeyCallback
321347
cfg.HostKeyAlgorithms = m.HostKeyAlgorithms
322348
return cfg, nil
323349
}
350+
351+
func (m *HostKeyCallbackHelper) SetHostKeyCallback(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) {
352+
return m.SetHostKeyCallbackAndAlgorithms(cfg)
353+
}

plumbing/transport/ssh/auth_method_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import (
44
"bufio"
55
"fmt"
66
"os"
7+
"reflect"
78
"runtime"
89
"slices"
910
"strings"
11+
"testing"
1012

1113
"github.com/go-git/go-billy/v5/osfs"
1214
"github.com/go-git/go-billy/v5/util"
15+
"github.com/stretchr/testify/assert"
16+
"github.com/stretchr/testify/require"
1317
"golang.org/x/crypto/ssh"
1418
"golang.org/x/crypto/ssh/testdata"
1519

@@ -317,3 +321,100 @@ func (*SuiteCommon) TestNewKnownHostsDbWithCert(c *C) {
317321
}
318322
}
319323
}
324+
325+
func TestHostKeyCallbackHelper(t *testing.T) {
326+
cb1 := ssh.FixedHostKey(nil)
327+
tests := []struct {
328+
name string
329+
cb ssh.HostKeyCallback
330+
algos []string
331+
fallback func(files ...string) (ssh.HostKeyCallback, error)
332+
cc *ssh.ClientConfig
333+
want *ssh.ClientConfig
334+
wantErr string
335+
}{
336+
{
337+
name: "keep existing callback if set",
338+
cb: cb1,
339+
cc: &ssh.ClientConfig{},
340+
want: &ssh.ClientConfig{
341+
HostKeyCallback: cb1,
342+
},
343+
},
344+
{
345+
name: "create new client config is one isn't provided",
346+
cb: cb1,
347+
cc: nil,
348+
want: &ssh.ClientConfig{
349+
HostKeyCallback: cb1,
350+
},
351+
},
352+
{
353+
name: "respect pre-set algos",
354+
cb: cb1,
355+
algos: []string{"foo"},
356+
cc: &ssh.ClientConfig{},
357+
want: &ssh.ClientConfig{
358+
HostKeyCallback: cb1,
359+
HostKeyAlgorithms: []string{"foo"},
360+
},
361+
},
362+
{
363+
name: "no callback is set, call fallback",
364+
cc: &ssh.ClientConfig{},
365+
fallback: func(files ...string) (ssh.HostKeyCallback, error) {
366+
return cb1, nil
367+
},
368+
want: &ssh.ClientConfig{
369+
HostKeyCallback: cb1,
370+
},
371+
},
372+
{
373+
name: "no callback is set with nil client config",
374+
fallback: func(files ...string) (ssh.HostKeyCallback, error) {
375+
return cb1, nil
376+
},
377+
want: &ssh.ClientConfig{
378+
HostKeyCallback: cb1,
379+
},
380+
},
381+
{
382+
name: "algos with no callback, call fallback",
383+
algos: []string{"bar"},
384+
cc: &ssh.ClientConfig{},
385+
fallback: func(files ...string) (ssh.HostKeyCallback, error) {
386+
return cb1, nil
387+
},
388+
want: &ssh.ClientConfig{
389+
HostKeyCallback: cb1,
390+
HostKeyAlgorithms: []string{"bar"},
391+
},
392+
},
393+
}
394+
395+
for _, tc := range tests {
396+
t.Run(tc.name, func(t *testing.T) {
397+
helper := HostKeyCallbackHelper{
398+
HostKeyCallback: tc.cb,
399+
HostKeyAlgorithms: tc.algos,
400+
fallback: tc.fallback,
401+
}
402+
403+
got, gotErr := helper.SetHostKeyCallback(tc.cc)
404+
405+
if tc.wantErr == "" {
406+
require.NoError(t, gotErr)
407+
require.NotNil(t, got)
408+
409+
wantFunc := runtime.FuncForPC(reflect.ValueOf(tc.want.HostKeyCallback).Pointer()).Name()
410+
gotFunc := runtime.FuncForPC(reflect.ValueOf(got.HostKeyCallback).Pointer()).Name()
411+
assert.Equal(t, wantFunc, gotFunc)
412+
413+
assert.Equal(t, tc.want.HostKeyAlgorithms, got.HostKeyAlgorithms)
414+
} else {
415+
assert.ErrorContains(t, gotErr, tc.wantErr)
416+
assert.Nil(t, got)
417+
}
418+
})
419+
}
420+
}

0 commit comments

Comments
 (0)
0