99 lines
2.7 KiB
Go
99 lines
2.7 KiB
Go
package deployment
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
func TestSSHFactoryDefaultNegotiatesOnce(t *testing.T) {
|
|
for _, reject := range []bool{false, true} {
|
|
name := "accepted"
|
|
if reject {
|
|
name = "rejected"
|
|
}
|
|
t.Run(name, func(t *testing.T) {
|
|
_, privateKey := newTestSSHSigner(t)
|
|
hostSigner, _ := newTestSSHSigner(t)
|
|
server := startTestSSHServer(t, func(ssh.PublicKey) error {
|
|
if reject {
|
|
return errors.ErrUnsupported
|
|
}
|
|
return nil
|
|
}, hostSigner)
|
|
factory := SSHFactory{
|
|
Secrets: staticSecretReader{"secret://test": {"private_key": privateKey}},
|
|
Timeout: 2 * time.Second,
|
|
}
|
|
client, err := factory.ConnectShell(t.Context(), testSSHServerModel(
|
|
server, "secret://test", ssh.FingerprintSHA256(hostSigner.PublicKey()),
|
|
))
|
|
if client != nil {
|
|
defer client.Close()
|
|
}
|
|
if (err != nil) != reject {
|
|
t.Fatalf("reject=%t err=%v", reject, err)
|
|
}
|
|
if got := server.accepted.Load(); got != 1 {
|
|
t.Fatalf("connections=%d; want=1", got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSSHSingleNegotiationFallsBackToRegisteredFingerprint(t *testing.T) {
|
|
clientSigner, _ := newTestSSHSigner(t)
|
|
ecdsaHostSigner := newTestECDSAHostSigner(t)
|
|
ed25519HostSigner, _ := newTestSSHSigner(t)
|
|
var authenticated atomic.Int32
|
|
server := startTestSSHServer(t, func(ssh.PublicKey) error {
|
|
authenticated.Add(1)
|
|
return nil
|
|
}, ecdsaHostSigner, ed25519HostSigner)
|
|
ctx, cancel := context.WithTimeout(t.Context(), 2*time.Second)
|
|
defer cancel()
|
|
client, err := connectSSHClient(ctx,
|
|
testSSHServerModel(server, "secret://test", ssh.FingerprintSHA256(ed25519HostSigner.PublicKey())),
|
|
[]ssh.AuthMethod{ssh.PublicKeys(clientSigner)},
|
|
[]string{ssh.KeyAlgoECDSA256, ssh.KeyAlgoED25519}, true,
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer client.Close()
|
|
if got := server.accepted.Load(); got != 3 {
|
|
t.Fatalf("connections=%d; want=3", got)
|
|
}
|
|
if got := authenticated.Load(); got != 1 {
|
|
t.Fatalf("authenticated=%d; want=1", got)
|
|
}
|
|
}
|
|
|
|
func TestSSHFactoryDefaultRejectsUnknownFingerprintBeforeAuthentication(t *testing.T) {
|
|
_, privateKey := newTestSSHSigner(t)
|
|
hostSigner, _ := newTestSSHSigner(t)
|
|
var authenticated atomic.Int32
|
|
server := startTestSSHServer(t, func(ssh.PublicKey) error {
|
|
authenticated.Add(1)
|
|
return nil
|
|
}, hostSigner)
|
|
factory := SSHFactory{
|
|
Secrets: staticSecretReader{"secret://test": {"private_key": privateKey}},
|
|
Timeout: 2 * time.Second,
|
|
}
|
|
client, err := factory.ConnectShell(t.Context(), testSSHServerModel(server, "secret://test", "SHA256:unregistered"))
|
|
if client != nil {
|
|
defer client.Close()
|
|
}
|
|
if err == nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := authenticated.Load(); got != 0 {
|
|
t.Fatalf("authenticated=%d; want=0", got)
|
|
}
|
|
}
|