lfsapi: return null cred helper if cred helper isn't used for a req
This commit is contained in:
parent
c8b16f965c
commit
28ff509488
@ -21,29 +21,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) DoWithAuth(remote string, req *http.Request) (*http.Response, error) {
|
func (c *Client) DoWithAuth(remote string, req *http.Request) (*http.Response, error) {
|
||||||
credHelper := c.Credentials
|
apiEndpoint, access, credHelper, credsURL, creds, err := c.getCreds(remote, req)
|
||||||
if credHelper == nil {
|
|
||||||
var err error
|
|
||||||
credHelper, err = getCredentialHelper(c.osEnv, c.gitEnv)
|
|
||||||
if err != nil {
|
|
||||||
tracerx.Printf("error getting credential helper: %s", err)
|
|
||||||
}
|
|
||||||
if credHelper == nil {
|
|
||||||
credHelper = defaultCredentialHelper
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
netrcFinder := c.Netrc
|
|
||||||
if netrcFinder == nil {
|
|
||||||
netrcFinder = defaultNetrcFinder
|
|
||||||
}
|
|
||||||
|
|
||||||
ef := c.Endpoints
|
|
||||||
if ef == nil {
|
|
||||||
ef = defaultEndpointFinder
|
|
||||||
}
|
|
||||||
|
|
||||||
apiEndpoint, access, creds, credsURL, err := getCreds(credHelper, netrcFinder, ef, remote, req)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -101,32 +79,48 @@ func (c *Client) doWithCreds(req *http.Request, credHelper CredentialHelper, cre
|
|||||||
// 3. The Git Remote URL, which should be something like "https://git.com/repo.git"
|
// 3. The Git Remote URL, which should be something like "https://git.com/repo.git"
|
||||||
// This URL is used for the Git Credential Helper. This way existing https
|
// This URL is used for the Git Credential Helper. This way existing https
|
||||||
// Git remote credentials can be re-used for LFS.
|
// Git remote credentials can be re-used for LFS.
|
||||||
func getCreds(credHelper CredentialHelper, netrcFinder NetrcFinder, ef EndpointFinder, remote string, req *http.Request) (Endpoint, Access, Creds, *url.URL, error) {
|
func (c *Client) getCreds(remote string, req *http.Request) (Endpoint, Access, CredentialHelper, *url.URL, Creds, error) {
|
||||||
|
ef := c.Endpoints
|
||||||
|
if ef == nil {
|
||||||
|
ef = defaultEndpointFinder
|
||||||
|
}
|
||||||
|
|
||||||
|
netrcFinder := c.Netrc
|
||||||
|
if netrcFinder == nil {
|
||||||
|
netrcFinder = defaultNetrcFinder
|
||||||
|
}
|
||||||
|
|
||||||
operation := getReqOperation(req)
|
operation := getReqOperation(req)
|
||||||
apiEndpoint := ef.Endpoint(operation, remote)
|
apiEndpoint := ef.Endpoint(operation, remote)
|
||||||
access := ef.AccessFor(apiEndpoint.Url)
|
access := ef.AccessFor(apiEndpoint.Url)
|
||||||
|
|
||||||
if access != NTLMAccess {
|
if access != NTLMAccess {
|
||||||
if requestHasAuth(req) || setAuthFromNetrc(netrcFinder, req) || access == NoneAccess {
|
if requestHasAuth(req) || setAuthFromNetrc(netrcFinder, req) || access == NoneAccess {
|
||||||
return apiEndpoint, access, nil, nil, nil
|
return apiEndpoint, access, nullCreds, nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
credsURL, err := getCredURLForAPI(ef, operation, remote, apiEndpoint, req)
|
credsURL, err := getCredURLForAPI(ef, operation, remote, apiEndpoint, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiEndpoint, access, nil, nil, errors.Wrap(err, "creds")
|
return apiEndpoint, access, nullCreds, nil, nil, errors.Wrap(err, "creds")
|
||||||
}
|
}
|
||||||
|
|
||||||
if credsURL == nil {
|
if credsURL == nil {
|
||||||
return apiEndpoint, access, nil, nil, nil
|
return apiEndpoint, access, nullCreds, nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
creds, err := fillGitCreds(credHelper, ef, req, credsURL)
|
credHelper, creds, err := c.getGitCreds(ef, req, credsURL)
|
||||||
return apiEndpoint, access, creds, credsURL, err
|
if err == nil {
|
||||||
|
tracerx.Printf("Filled credentials for %s", credsURL)
|
||||||
|
setRequestAuth(req, creds["username"], creds["password"])
|
||||||
}
|
}
|
||||||
|
return apiEndpoint, access, credHelper, credsURL, creds, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NTLM ONLY
|
||||||
|
|
||||||
credsURL, err := url.Parse(apiEndpoint.Url)
|
credsURL, err := url.Parse(apiEndpoint.Url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiEndpoint, access, nil, nil, errors.Wrap(err, "creds")
|
return apiEndpoint, access, nullCreds, nil, nil, errors.Wrap(err, "creds")
|
||||||
}
|
}
|
||||||
|
|
||||||
if netrcMachine := getAuthFromNetrc(netrcFinder, req); netrcMachine != nil {
|
if netrcMachine := getAuthFromNetrc(netrcFinder, req); netrcMachine != nil {
|
||||||
@ -138,20 +132,16 @@ func getCreds(credHelper CredentialHelper, netrcFinder NetrcFinder, ef EndpointF
|
|||||||
"source": "netrc",
|
"source": "netrc",
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiEndpoint, access, creds, credsURL, nil
|
return apiEndpoint, access, nullCreds, credsURL, creds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
creds, err := getGitCreds(credHelper, ef, req, credsURL)
|
// NTLM uses creds to create the session
|
||||||
return apiEndpoint, access, creds, credsURL, err
|
credHelper, creds, err := c.getGitCreds(ef, req, credsURL)
|
||||||
}
|
return apiEndpoint, access, credHelper, credsURL, creds, err
|
||||||
|
|
||||||
func getGitCreds(credHelper CredentialHelper, ef EndpointFinder, req *http.Request, u *url.URL) (Creds, error) {
|
|
||||||
path := strings.TrimPrefix(u.Path, "/")
|
|
||||||
input := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
|
|
||||||
if u.User != nil && u.User.Username() != "" {
|
|
||||||
input["username"] = u.User.Username()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) getGitCreds(ef EndpointFinder, req *http.Request, u *url.URL) (CredentialHelper, Creds, error) {
|
||||||
|
credHelper, input := c.getCredentialHelper(u)
|
||||||
creds, err := credHelper.Fill(input)
|
creds, err := credHelper.Fill(input)
|
||||||
if creds == nil || len(creds) < 1 {
|
if creds == nil || len(creds) < 1 {
|
||||||
errmsg := fmt.Sprintf("Git credentials for %s not found", u)
|
errmsg := fmt.Sprintf("Git credentials for %s not found", u)
|
||||||
@ -163,17 +153,7 @@ func getGitCreds(credHelper CredentialHelper, ef EndpointFinder, req *http.Reque
|
|||||||
err = errors.New(errmsg)
|
err = errors.New(errmsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return creds, err
|
return credHelper, creds, err
|
||||||
}
|
|
||||||
|
|
||||||
func fillGitCreds(credHelper CredentialHelper, ef EndpointFinder, req *http.Request, u *url.URL) (Creds, error) {
|
|
||||||
creds, err := getGitCreds(credHelper, ef, req, u)
|
|
||||||
if err == nil {
|
|
||||||
tracerx.Printf("Filled credentials for %s", u)
|
|
||||||
setRequestAuth(req, creds["username"], creds["password"])
|
|
||||||
}
|
|
||||||
|
|
||||||
return creds, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAuthFromNetrc(netrcFinder NetrcFinder, req *http.Request) *netrc.Machine {
|
func getAuthFromNetrc(netrcFinder NetrcFinder, req *http.Request) *netrc.Machine {
|
||||||
|
@ -517,8 +517,10 @@ func TestGetCreds(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
credHelper := &fakeCredentialFiller{}
|
client := &Client{
|
||||||
netrcFinder := &fakeNetrc{}
|
Credentials: &fakeCredentialFiller{},
|
||||||
|
Netrc: &fakeNetrc{},
|
||||||
|
}
|
||||||
for desc, test := range tests {
|
for desc, test := range tests {
|
||||||
t.Log(desc)
|
t.Log(desc)
|
||||||
req, err := http.NewRequest(test.Method, test.Href, nil)
|
req, err := http.NewRequest(test.Method, test.Href, nil)
|
||||||
@ -531,8 +533,8 @@ func TestGetCreds(t *testing.T) {
|
|||||||
req.Header.Set(key, value)
|
req.Header.Set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
ef := NewEndpointFinder(NewContext(nil, nil, test.Config))
|
client.Endpoints = NewEndpointFinder(NewContext(nil, nil, test.Config))
|
||||||
endpoint, access, creds, credsURL, err := getCreds(credHelper, netrcFinder, ef, test.Remote, req)
|
endpoint, access, _, credsURL, creds, err := client.getCreds(test.Remote, req)
|
||||||
if !assert.Nil(t, err) {
|
if !assert.Nil(t, err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
100
lfsapi/creds.go
100
lfsapi/creds.go
@ -8,86 +8,61 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/git-lfs/git-lfs/config"
|
|
||||||
"github.com/git-lfs/git-lfs/errors"
|
"github.com/git-lfs/git-lfs/errors"
|
||||||
"github.com/rubyist/tracerx"
|
"github.com/rubyist/tracerx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// credsConfig supplies configuration options pertaining to the authorization
|
|
||||||
// process in package lfsapi.
|
|
||||||
type credsConfig struct {
|
|
||||||
// AskPass is a string containing an executable name as well as a
|
|
||||||
// program arguments.
|
|
||||||
//
|
|
||||||
// See: https://git-scm.com/docs/gitcredentials#_requesting_credentials
|
|
||||||
// for more.
|
|
||||||
AskPass string `os:"GIT_ASKPASS" git:"core.askpass" os:"SSH_ASKPASS"`
|
|
||||||
// Helper is a string defining the credential helper that Git should use.
|
|
||||||
Helper string `git:"credential.helper"`
|
|
||||||
// Cached is a boolean determining whether or not to enable the
|
|
||||||
// credential cacher.
|
|
||||||
Cached bool
|
|
||||||
// SkipPrompt is a boolean determining whether or not to prompt the user
|
|
||||||
// for a password.
|
|
||||||
SkipPrompt bool `os:"GIT_TERMINAL_PROMPT"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCredentialHelper parses a 'credsConfig' from the git and OS environments,
|
// getCredentialHelper parses a 'credsConfig' from the git and OS environments,
|
||||||
// returning the appropriate CredentialHelper to authenticate requests with.
|
// returning the appropriate CredentialHelper to authenticate requests with.
|
||||||
//
|
//
|
||||||
// It returns an error if any configuration was invalid, or otherwise
|
// It returns an error if any configuration was invalid, or otherwise
|
||||||
// un-useable.
|
// un-useable.
|
||||||
func getCredentialHelper(osEnv, gitEnv config.Environment) (CredentialHelper, error) {
|
func (c *Client) getCredentialHelper(u *url.URL) (CredentialHelper, Creds) {
|
||||||
ccfg, err := getCredentialConfig(osEnv, gitEnv)
|
path := strings.TrimPrefix(u.Path, "/")
|
||||||
if err != nil {
|
input := Creds{"protocol": u.Scheme, "host": u.Host, "path": path}
|
||||||
return nil, err
|
if u.User != nil && u.User.Username() != "" {
|
||||||
|
input["username"] = u.User.Username()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Credentials != nil {
|
||||||
|
return c.Credentials, input
|
||||||
|
}
|
||||||
|
|
||||||
|
askpass, ok := c.osEnv.Get("GIT_ASKPASS")
|
||||||
|
if !ok {
|
||||||
|
askpass, ok = c.gitEnv.Get("core.askpass")
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
askpass, ok = c.osEnv.Get("SSH_ASKPASS")
|
||||||
|
}
|
||||||
|
helper, _ := c.gitEnv.Get("credential.helper")
|
||||||
|
cached := c.gitEnv.Bool("lfs.cachecredentials", true)
|
||||||
|
skipPrompt := c.osEnv.Bool("GIT_TERMINAL_PROMPT", false)
|
||||||
|
|
||||||
var hs []CredentialHelper
|
var hs []CredentialHelper
|
||||||
if len(ccfg.Helper) == 0 && len(ccfg.AskPass) > 0 {
|
if len(helper) == 0 && len(askpass) > 0 {
|
||||||
hs = append(hs, &AskPassCredentialHelper{
|
hs = append(hs, &AskPassCredentialHelper{
|
||||||
Program: ccfg.AskPass,
|
Program: askpass,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var h CredentialHelper
|
var h CredentialHelper
|
||||||
h = &commandCredentialHelper{
|
h = &commandCredentialHelper{
|
||||||
SkipPrompt: ccfg.SkipPrompt,
|
SkipPrompt: skipPrompt,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ccfg.Cached {
|
if cached {
|
||||||
h = withCredentialCache(h)
|
h = withCredentialCache(h)
|
||||||
}
|
}
|
||||||
hs = append(hs, h)
|
hs = append(hs, h)
|
||||||
|
|
||||||
switch len(hs) {
|
switch len(hs) {
|
||||||
case 0:
|
case 0:
|
||||||
return nil, nil
|
return defaultCredentialHelper, input
|
||||||
case 1:
|
case 1:
|
||||||
return hs[0], nil
|
return hs[0], input
|
||||||
}
|
}
|
||||||
return CredentialHelpers(hs), nil
|
return CredentialHelpers(hs), input
|
||||||
}
|
|
||||||
|
|
||||||
// getCredentialConfig parses a *credsConfig given the OS and Git
|
|
||||||
// configurations.
|
|
||||||
func getCredentialConfig(o, g config.Environment) (*credsConfig, error) {
|
|
||||||
askpass, ok := o.Get("GIT_ASKPASS")
|
|
||||||
if !ok {
|
|
||||||
askpass, ok = g.Get("core.askpass")
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
askpass, ok = o.Get("SSH_ASKPASS")
|
|
||||||
}
|
|
||||||
helper, _ := g.Get("credential.helper")
|
|
||||||
what := &credsConfig{
|
|
||||||
AskPass: askpass,
|
|
||||||
Helper: helper,
|
|
||||||
Cached: g.Bool("lfs.cachecredentials", true),
|
|
||||||
SkipPrompt: o.Bool("GIT_TERMINAL_PROMPT", false),
|
|
||||||
}
|
|
||||||
|
|
||||||
return what, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CredentialHelpers is a []CredentialHelper that iterates through each
|
// CredentialHelpers is a []CredentialHelper that iterates through each
|
||||||
@ -332,6 +307,8 @@ func (h *commandCredentialHelper) Reject(creds Creds) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *commandCredentialHelper) Approve(creds Creds) error {
|
func (h *commandCredentialHelper) Approve(creds Creds) error {
|
||||||
|
tracerx.Printf("creds: git credential approve (%q, %q, %q)",
|
||||||
|
creds["protocol"], creds["host"], creds["path"])
|
||||||
_, err := h.exec("approve", creds)
|
_, err := h.exec("approve", creds)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -383,3 +360,22 @@ func (h *commandCredentialHelper) exec(subcommand string, input Creds) (Creds, e
|
|||||||
|
|
||||||
return creds, nil
|
return creds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nullCredentialHelper struct{}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nullCredError = errors.New("No credential helper configured")
|
||||||
|
nullCreds = &nullCredentialHelper{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *nullCredentialHelper) Fill(input Creds) (Creds, error) {
|
||||||
|
return nil, nullCredError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *nullCredentialHelper) Approve(creds Creds) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *nullCredentialHelper) Reject(creds Creds) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user