From 373e597885919fdc4684847e0a96df2d104896a3 Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Fri, 21 Apr 2017 11:20:01 +0200 Subject: transport: ssh, NewPublicKeys helper --- plumbing/transport/ssh/auth_method.go | 69 ++++++++++++++++++++---------- plumbing/transport/ssh/auth_method_test.go | 22 ++++++++++ 2 files changed, 68 insertions(+), 23 deletions(-) (limited to 'plumbing/transport/ssh') diff --git a/plumbing/transport/ssh/auth_method.go b/plumbing/transport/ssh/auth_method.go index 82e3453..ad92ee1 100644 --- a/plumbing/transport/ssh/auth_method.go +++ b/plumbing/transport/ssh/auth_method.go @@ -3,6 +3,7 @@ package ssh import ( "errors" "fmt" + "io/ioutil" "net" "os" "os/user" @@ -13,6 +14,8 @@ import ( "golang.org/x/crypto/ssh/agent" ) +const DefaultUsername = "git" + var ErrEmptySSHAgentAddr = errors.New("SSH_AUTH_SOCK env variable is required") // AuthMethod is the interface all auth methods for the ssh client @@ -102,14 +105,35 @@ func (a *PasswordCallback) clientConfig() *ssh.ClientConfig { } } -// PublicKeys implements AuthMethod by using the given -// key pairs. +// PublicKeys implements AuthMethod by using the given key pairs. type PublicKeys struct { User string Signer ssh.Signer baseAuthMethod } +// NewPublicKeys returns a PublicKeys from a PEM encoded private key. It +// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys. +func NewPublicKeys(user string, pemBytes []byte) (AuthMethod, error) { + signer, err := ssh.ParsePrivateKey(pemBytes) + if err != nil { + return nil, err + } + + return &PublicKeys{User: user, Signer: signer}, nil +} + +// NewPublicKeysFromFile returns a PublicKeys from a file containing a PEM +// encoded private key. +func NewPublicKeysFromFile(user string, pemFile string) (AuthMethod, error) { + bytes, err := ioutil.ReadFile(pemFile) + if err != nil { + return nil, err + } + + return NewPublicKeys(user, bytes) +} + func (a *PublicKeys) Name() string { return PublicKeysName } @@ -133,28 +157,12 @@ type PublicKeysCallback struct { baseAuthMethod } -func (a *PublicKeysCallback) Name() string { - return PublicKeysCallbackName -} - -func (a *PublicKeysCallback) String() string { - return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) -} - -func (a *PublicKeysCallback) clientConfig() *ssh.ClientConfig { - return &ssh.ClientConfig{ - User: a.User, - Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)}, - } -} - -const DefaultSSHUsername = "git" - -// NewSSHAgentAuth opens a pipe with the SSH agent and uses the pipe -// as the implementer of the public key callback function. -func NewSSHAgentAuth(user string) (*PublicKeysCallback, error) { +// NewSSHAgentAuth returns a PublicKeysCallback based on a SSH agent, it opens +// a pipe with the SSH agent and uses the pipe as the implementer of the public +// key callback function. +func NewSSHAgentAuth(user string) (AuthMethod, error) { if user == "" { - user = DefaultSSHUsername + user = DefaultUsername } sshAgentAddr := os.Getenv("SSH_AUTH_SOCK") @@ -173,6 +181,21 @@ func NewSSHAgentAuth(user string) (*PublicKeysCallback, error) { }, nil } +func (a *PublicKeysCallback) Name() string { + return PublicKeysCallbackName +} + +func (a *PublicKeysCallback) String() string { + return fmt.Sprintf("user: %s, name: %s", a.User, a.Name()) +} + +func (a *PublicKeysCallback) clientConfig() *ssh.ClientConfig { + return &ssh.ClientConfig{ + User: a.User, + Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)}, + } +} + // NewKnownHostsCallback returns ssh.HostKeyCallback based on a file based on a // know_hosts file. http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT // diff --git a/plumbing/transport/ssh/auth_method_test.go b/plumbing/transport/ssh/auth_method_test.go index 412e721..43b34df 100644 --- a/plumbing/transport/ssh/auth_method_test.go +++ b/plumbing/transport/ssh/auth_method_test.go @@ -2,8 +2,11 @@ package ssh import ( "fmt" + "io/ioutil" "os" + "golang.org/x/crypto/ssh/testdata" + . "gopkg.in/check.v1" ) @@ -104,3 +107,22 @@ func (s *SuiteCommon) TestNewSSHAgentAuth(c *C) { c.Assert(k, IsNil) c.Assert(err, Equals, ErrEmptySSHAgentAddr) } + +func (*SuiteCommon) TestNewPublicKeys(c *C) { + auth, err := NewPublicKeys("foo", testdata.PEMBytes["rsa"]) + c.Assert(err, IsNil) + c.Assert(auth, NotNil) +} + +func (*SuiteCommon) TestNewPublicKeysFromFile(c *C) { + f, err := ioutil.TempFile("", "ssh-test") + c.Assert(err, IsNil) + _, err = f.Write(testdata.PEMBytes["rsa"]) + c.Assert(err, IsNil) + c.Assert(f.Close(), IsNil) + defer os.RemoveAll(f.Name()) + + auth, err := NewPublicKeysFromFile("foo", f.Name()) + c.Assert(err, IsNil) + c.Assert(auth, NotNil) +} -- cgit