Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 46 additions & 23 deletions plumbing/transport/ssh/auth_method.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ssh
import (
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"os/user"
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -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")
Expand All @@ -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
//
Expand Down
22 changes: 22 additions & 0 deletions plumbing/transport/ssh/auth_method_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package ssh

import (
"fmt"
"io/ioutil"
"os"

"golang.org/x/crypto/ssh/testdata"

. "gopkg.in/check.v1"
)

Expand Down Expand Up @@ -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)
}