diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2016-08-31 23:42:36 +0200 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2016-08-31 23:42:36 +0200 |
commit | 5bed3e8fab965738f3f55bb01d15cd4748c26066 (patch) | |
tree | 14dbeb9f92b4ab16ab99268156c3336b53bcfce4 | |
parent | a82239a71a2cfc7a55af253d11c28fcec73a3039 (diff) | |
download | go-git-5bed3e8fab965738f3f55bb01d15cd4748c26066.tar.gz |
clients: default Auth methods
-rw-r--r-- | clients/common/common.go | 2 | ||||
-rw-r--r-- | clients/common_test.go | 2 | ||||
-rw-r--r-- | clients/http/common.go | 7 | ||||
-rw-r--r-- | clients/http/git_upload_pack.go | 31 | ||||
-rw-r--r-- | clients/http/git_upload_pack_test.go | 21 | ||||
-rw-r--r-- | clients/ssh/auth_method.go | 10 | ||||
-rw-r--r-- | clients/ssh/git_upload_pack.go | 96 | ||||
-rw-r--r-- | clients/ssh/git_upload_pack_test.go | 4 | ||||
-rw-r--r-- | common_test.go | 3 |
9 files changed, 115 insertions, 61 deletions
diff --git a/clients/common/common.go b/clients/common/common.go index 0d0026b..b5e6152 100644 --- a/clients/common/common.go +++ b/clients/common/common.go @@ -26,7 +26,7 @@ const GitUploadPackServiceName = "git-upload-pack" type GitUploadPackService interface { Connect() error - ConnectWithAuth(AuthMethod) error + SetAuth(AuthMethod) error Info() (*GitUploadPackInfo, error) Fetch(*GitUploadPackRequest) (io.ReadCloser, error) Disconnect() error diff --git a/clients/common_test.go b/clients/common_test.go index 0381f63..59fc300 100644 --- a/clients/common_test.go +++ b/clients/common_test.go @@ -64,7 +64,7 @@ func (s *dummyProtocolService) Connect() error { return nil } -func (s *dummyProtocolService) ConnectWithAuth(auth common.AuthMethod) error { +func (s *dummyProtocolService) SetAuth(auth common.AuthMethod) error { return nil } diff --git a/clients/http/common.go b/clients/http/common.go index 703208b..483308a 100644 --- a/clients/http/common.go +++ b/clients/http/common.go @@ -9,15 +9,18 @@ import ( "gopkg.in/src-d/go-git.v4/core" ) +// HTTPAuthMethod concrete implementation of common.AuthMethod for HTTP services type HTTPAuthMethod interface { common.AuthMethod setAuth(r *http.Request) } +// BasicAuth represent a HTTP basic auth type BasicAuth struct { username, password string } +// NewBasicAuth returns a BasicAuth base on the given user and password func NewBasicAuth(username, password string) *BasicAuth { return &BasicAuth{username, password} } @@ -26,6 +29,7 @@ func (a *BasicAuth) setAuth(r *http.Request) { r.SetBasicAuth(a.username, a.password) } +// Name name of the auth func (a *BasicAuth) Name() string { return "http-basic-auth" } @@ -39,10 +43,12 @@ func (a *BasicAuth) String() string { return fmt.Sprintf("%s - %s:%s", a.Name(), a.username, masked) } +// HTTPError a dedicated error to return errors bases on status codes type HTTPError struct { Response *http.Response } +// NewHTTPError returns a new HTTPError based on a http response func NewHTTPError(r *http.Response) error { if r.StatusCode >= 200 && r.StatusCode < 300 { return nil @@ -59,6 +65,7 @@ func NewHTTPError(r *http.Response) error { return core.NewUnexpectedError(err) } +// StatusCode returns the status code of the response func (e *HTTPError) StatusCode() int { return e.Response.StatusCode } diff --git a/clients/http/git_upload_pack.go b/clients/http/git_upload_pack.go index bca4534..888d279 100644 --- a/clients/http/git_upload_pack.go +++ b/clients/http/git_upload_pack.go @@ -12,24 +12,47 @@ import ( "gopkg.in/src-d/go-git.v4/formats/pktline" ) +// GitUploadPackService git-upoad-pack service over HTTP type GitUploadPackService struct { client *http.Client endpoint common.Endpoint auth HTTPAuthMethod } +// NewGitUploadPackService connects to a git-upload-pack service over HTTP, the +// auth is extracted from the URL, or can be provided using the SetAuth method func NewGitUploadPackService(endpoint common.Endpoint) common.GitUploadPackService { - return &GitUploadPackService{ + s := &GitUploadPackService{ client: http.DefaultClient, endpoint: endpoint, } + + s.setBasicAuthFromEndpoint() + return s } +// Connect has not any effect, is here just for meet the interface func (s *GitUploadPackService) Connect() error { return nil } -func (s *GitUploadPackService) ConnectWithAuth(auth common.AuthMethod) error { +func (s *GitUploadPackService) setBasicAuthFromEndpoint() { + info := s.endpoint.User + if info == nil { + return + } + + p, ok := info.Password() + if !ok { + return + } + + u := info.Username() + s.auth = NewBasicAuth(u, p) +} + +// SetAuth sets the AuthMethod +func (s *GitUploadPackService) SetAuth(auth common.AuthMethod) error { httpAuth, ok := auth.(HTTPAuthMethod) if !ok { return common.ErrInvalidAuthMethod @@ -39,6 +62,7 @@ func (s *GitUploadPackService) ConnectWithAuth(auth common.AuthMethod) error { return nil } +// Info returns the references info and capabilities from the service func (s *GitUploadPackService) Info() (*common.GitUploadPackInfo, error) { url := fmt.Sprintf( "%s/info/refs?service=%s", @@ -56,6 +80,7 @@ func (s *GitUploadPackService) Info() (*common.GitUploadPackInfo, error) { return i, i.Decode(pktline.NewDecoder(res.Body)) } +// Fetch request and returns a reader to a packfile func (s *GitUploadPackService) Fetch(r *common.GitUploadPackRequest) (io.ReadCloser, error) { url := fmt.Sprintf( "%s/%s", @@ -98,6 +123,7 @@ func (s *GitUploadPackService) discardResponseInfo(r io.Reader) error { return nil } + func (s *GitUploadPackService) doRequest(method, url string, content *strings.Reader) (*http.Response, error) { var body io.Reader if content != nil { @@ -145,6 +171,7 @@ func (s *GitUploadPackService) applyAuthToRequest(req *http.Request) { s.auth.setAuth(req) } +// Disconnect do nothing func (s *GitUploadPackService) Disconnect() (err error) { return nil } diff --git a/clients/http/git_upload_pack_test.go b/clients/http/git_upload_pack_test.go index e344a49..579419f 100644 --- a/clients/http/git_upload_pack_test.go +++ b/clients/http/git_upload_pack_test.go @@ -16,19 +16,30 @@ var _ = Suite(&RemoteSuite{}) func (s *RemoteSuite) SetUpSuite(c *C) { var err error - s.Endpoint, err = common.NewEndpoint("https://github.com/tyba/git-fixture") + s.Endpoint, err = common.NewEndpoint("https://github.com/git-fixtures/basic") c.Assert(err, IsNil) } +func (s *RemoteSuite) TestNewGitUploadPackServiceAuth(c *C) { + e, err := common.NewEndpoint("https://foo:bar@github.com/git-fixtures/basic") + c.Assert(err, IsNil) + + r := NewGitUploadPackService(e) + auth := r.(*GitUploadPackService).auth + + c.Assert(auth.String(), Equals, "http-basic-auth - foo:*******") +} + func (s *RemoteSuite) TestConnect(c *C) { r := NewGitUploadPackService(s.Endpoint) c.Assert(r.Connect(), IsNil) } -func (s *RemoteSuite) TestConnectWithAuth(c *C) { +func (s *RemoteSuite) TestSetAuth(c *C) { auth := &BasicAuth{} r := NewGitUploadPackService(s.Endpoint) - c.Assert(r.ConnectWithAuth(auth), IsNil) + r.SetAuth(auth) + c.Assert(auth, Equals, r.(*GitUploadPackService).auth) } type mockAuth struct{} @@ -36,9 +47,9 @@ type mockAuth struct{} func (*mockAuth) Name() string { return "" } func (*mockAuth) String() string { return "" } -func (s *RemoteSuite) TestConnectWithAuthWrongType(c *C) { +func (s *RemoteSuite) TestSetAuthWrongType(c *C) { r := NewGitUploadPackService(s.Endpoint) - c.Assert(r.ConnectWithAuth(&mockAuth{}), Equals, common.ErrInvalidAuthMethod) + c.Assert(r.SetAuth(&mockAuth{}), Equals, common.ErrInvalidAuthMethod) } func (s *RemoteSuite) TestInfoEmpty(c *C) { diff --git a/clients/ssh/auth_method.go b/clients/ssh/auth_method.go index e55283e..1ce45ef 100644 --- a/clients/ssh/auth_method.go +++ b/clients/ssh/auth_method.go @@ -138,16 +138,22 @@ func (a *PublicKeysCallback) clientConfig() *ssh.ClientConfig { } } +const DefaultSSHUsername = "git" + // Opens a pipe with the ssh agent and uses the pipe // as the implementer of the public key callback function. -func NewSSHAgentAuth() (*PublicKeysCallback, error) { +func NewSSHAgentAuth(user string) (*PublicKeysCallback, error) { + if user == "" { + user = DefaultSSHUsername + } + pipe, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) if err != nil { return nil, err } return &PublicKeysCallback{ - User: "git", + User: user, Callback: agent.NewClient(pipe).Signers, }, nil } diff --git a/clients/ssh/git_upload_pack.go b/clients/ssh/git_upload_pack.go index eb5926e..d83aadb 100644 --- a/clients/ssh/git_upload_pack.go +++ b/clients/ssh/git_upload_pack.go @@ -1,6 +1,4 @@ // Package ssh implements a ssh client for go-git. -// -// The Connect() method is not allowed in ssh, use ConnectWithAuth() instead. package ssh import ( @@ -10,13 +8,12 @@ import ( "fmt" "io" "io/ioutil" - "net/url" + "strings" "gopkg.in/src-d/go-git.v4/clients/common" "gopkg.in/src-d/go-git.v4/formats/pktline" "golang.org/x/crypto/ssh" - "gopkg.in/sourcegraph/go-vcsurl.v1" ) // New errors introduced by this package. @@ -32,79 +29,79 @@ var ( // GitUploadPackService holds the service information. // The zero value is safe to use. -// TODO: remove NewGitUploadPackService(). type GitUploadPackService struct { connected bool endpoint common.Endpoint - vcs *vcsurl.RepoInfo client *ssh.Client auth AuthMethod } -// NewGitUploadPackService initialises a GitUploadPackService. +// NewGitUploadPackService initialises a GitUploadPackService, func NewGitUploadPackService(endpoint common.Endpoint) common.GitUploadPackService { return &GitUploadPackService{endpoint: endpoint} } -// Connect cannot be used with SSH clients and always return -// ErrAuthRequired. Use ConnectWithAuth instead. +// Connect connects to the SSH server, unless a AuthMethod was set with SetAuth +// method, by default uses an auth method based on PublicKeysCallback, it +// connects to a SSH agent, using the address stored in the SSH_AUTH_SOCK +// environment var func (s *GitUploadPackService) Connect() error { - auth, err := NewSSHAgentAuth() - if err != nil { - return err - } - - return s.ConnectWithAuth(auth) -} - -// ConnectWithAuth connects to ep using SSH. Authentication is handled -// by auth. -func (s *GitUploadPackService) ConnectWithAuth(auth common.AuthMethod) (err error) { if s.connected { return ErrAlreadyConnected } - s.vcs, err = vcsurl.Parse(s.endpoint.String()) - if err != nil { + if err := s.setAuthFromEndpoint(); err != nil { return err } - url, err := vcsToURL(s.vcs) + var err error + s.client, err = ssh.Dial("tcp", s.getHostWithPort(), s.auth.clientConfig()) if err != nil { - return + return err } - var ok bool - s.auth, ok = auth.(AuthMethod) - if !ok { - return ErrInvalidAuthMethod + s.connected = true + return nil +} + +func (s *GitUploadPackService) getHostWithPort() string { + host := s.endpoint.Host + if strings.Index(s.endpoint.Host, ":") == -1 { + host += ":22" } - s.client, err = ssh.Dial("tcp", url.Host, s.auth.clientConfig()) + return host +} + +func (s *GitUploadPackService) setAuthFromEndpoint() error { + var u string + if info := s.endpoint.User; info != nil { + u = info.Username() + } + + var err error + s.auth, err = NewSSHAgentAuth(u) if err != nil { return err } - s.connected = true - return + return nil } -func vcsToURL(vcs *vcsurl.RepoInfo) (u *url.URL, err error) { - if vcs.VCS != vcsurl.Git { - return nil, ErrUnsupportedVCS - } - if vcs.RepoHost != vcsurl.GitHub { - return nil, ErrUnsupportedRepo +// SetAuth sets the AuthMethod +func (s *GitUploadPackService) SetAuth(auth common.AuthMethod) error { + var ok bool + s.auth, ok = auth.(AuthMethod) + if !ok { + return ErrInvalidAuthMethod } - s := "ssh://git@" + string(vcs.RepoHost) + ":22/" + vcs.FullName - u, err = url.Parse(s) - return + + return nil } -// Info returns the GitUploadPackInfo of the repository. -// The client must be connected with the repository (using -// the ConnectWithAuth() method) before using this -// method. +// Info returns the GitUploadPackInfo of the repository. The client must be +// connected with the repository (using the ConnectWithAuth() method) before +// using this method. func (s *GitUploadPackService) Info() (i *common.GitUploadPackInfo, err error) { if !s.connected { return nil, ErrNotConnected @@ -120,7 +117,7 @@ func (s *GitUploadPackService) Info() (i *common.GitUploadPackInfo, err error) { _ = session.Close() }() - out, err := session.Output("git-upload-pack " + s.vcs.FullName + ".git") + out, err := session.Output(s.getCommand()) if err != nil { return nil, err } @@ -169,7 +166,7 @@ func (s *GitUploadPackService) Fetch(r *common.GitUploadPackRequest) (rc io.Read return nil, err } - if err := session.Start("git-upload-pack " + s.vcs.FullName + ".git"); err != nil { + if err := session.Start(s.getCommand()); err != nil { return nil, err } @@ -209,3 +206,10 @@ func (s *GitUploadPackService) Fetch(r *common.GitUploadPackRequest) (rc io.Read buf := bytes.NewBuffer(data) return ioutil.NopCloser(buf), nil } + +func (s *GitUploadPackService) getCommand() string { + directory := s.endpoint.Path + directory = directory[1:len(directory)] + + return fmt.Sprintf("git-upload-pack %s", directory) +} diff --git a/clients/ssh/git_upload_pack_test.go b/clients/ssh/git_upload_pack_test.go index b26276d..0785af5 100644 --- a/clients/ssh/git_upload_pack_test.go +++ b/clients/ssh/git_upload_pack_test.go @@ -32,9 +32,9 @@ type mockAuth struct{} func (*mockAuth) Name() string { return "" } func (*mockAuth) String() string { return "" } -func (s *RemoteSuite) TestConnectWithAuthWrongType(c *C) { +func (s *RemoteSuite) TestSetAuthWrongType(c *C) { r := NewGitUploadPackService(s.Endpoint) - c.Assert(r.ConnectWithAuth(&mockAuth{}), Equals, ErrInvalidAuthMethod) + c.Assert(r.SetAuth(&mockAuth{}), Equals, ErrInvalidAuthMethod) } func (s *RemoteSuite) TestAlreadyConnected(c *C) { diff --git a/common_test.go b/common_test.go index e02e9d6..42b3310 100644 --- a/common_test.go +++ b/common_test.go @@ -45,8 +45,7 @@ func (p *MockGitUploadPackService) Connect() error { return nil } -func (p *MockGitUploadPackService) ConnectWithAuth(auth common.AuthMethod) error { - p.connected = true +func (p *MockGitUploadPackService) SetAuth(auth common.AuthMethod) error { p.auth = auth return nil } |