Permalink
Please
sign in to comment.
Browse files
creds: Add new NetrcCredentialHelper
This commit adds a new credential helper, NetrcCredentialHelper, to retrieve credentials from a .netrc file. This replaces the old .netrc authorization behaviour, which was done directly from the `doWithAuth()` code. Additionally, this commit moves all of the `.netrc` functionality out of `lfsapi` and into `creds`. This was done both because `creds` is now the logical place for the `.netrc` functionality, and to prevent an import cycle between `creds` and `lfsapi`.
- Loading branch information...
Showing
with
238 additions
and 216 deletions.
- +7 −1 creds/creds.go
- +1 −1 lfsapi/lfsapi_nix.go → creds/creds_nix.go
- +1 −1 lfsapi/lfsapi_windows.go → creds/creds_windows.go
- +130 −0 creds/netrc.go
- +82 −0 creds/netrc_test.go
- +1 −48 lfsapi/auth.go
- +0 −36 lfsapi/auth_test.go
- +0 −6 lfsapi/lfsapi.go
- +0 −34 lfsapi/netrc.go
- +0 −85 lfsapi/netrc_test.go
- +16 −4 t/t-credentials.sh
| @@ -1,5 +1,5 @@ | |||
| // +build !windows | |||
|
|
|||
| package lfsapi | |||
| package creds | |||
|
|
|||
| var netrcBasename = ".netrc" | |||
| @@ -1,5 +1,5 @@ | |||
| // +build windows | |||
|
|
|||
| package lfsapi | |||
| package creds | |||
|
|
|||
| var netrcBasename = "_netrc" | |||
| @@ -0,0 +1,130 @@ | |||
| package creds | |||
|
|
|||
| import ( | |||
| "net" | |||
| "os" | |||
| "path/filepath" | |||
| "strings" | |||
|
|
|||
| "github.com/git-lfs/git-lfs/config" | |||
| "github.com/git-lfs/go-netrc/netrc" | |||
| "github.com/rubyist/tracerx" | |||
| ) | |||
|
|
|||
| type NetrcFinder interface { | |||
| FindMachine(string) *netrc.Machine | |||
| } | |||
|
|
|||
| func ParseNetrc(osEnv config.Environment) (NetrcFinder, string, error) { | |||
| home, _ := osEnv.Get("HOME") | |||
| if len(home) == 0 { | |||
| return &noFinder{}, "", nil | |||
| } | |||
|
|
|||
| nrcfilename := filepath.Join(home, netrcBasename) | |||
| if _, err := os.Stat(nrcfilename); err != nil { | |||
| return &noFinder{}, nrcfilename, nil | |||
| } | |||
|
|
|||
| f, err := netrc.ParseFile(nrcfilename) | |||
| return f, nrcfilename, err | |||
| } | |||
|
|
|||
| type noFinder struct{} | |||
|
|
|||
| func (f *noFinder) FindMachine(host string) *netrc.Machine { | |||
| return nil | |||
| } | |||
|
|
|||
| // NetrcCredentialHelper retrieves credentials from a .netrc file | |||
| type netrcCredentialHelper struct { | |||
| netrcFinder NetrcFinder | |||
| skip map[string]bool | |||
| } | |||
|
|
|||
| var defaultNetrcFinder = &noFinder{} | |||
|
|
|||
| // NewNetrcCredentialHelper creates a new netrc credential helper using a | |||
| // .netrc file gleaned from the OS environment | |||
| func newNetrcCredentialHelper(osEnv config.Environment) *netrcCredentialHelper { | |||
| netrcFinder, netrcfile, err := ParseNetrc(osEnv) | |||
| if err != nil { | |||
| tracerx.Printf("bad netrc file %s: %s", netrcfile, err) | |||
| return nil | |||
| } | |||
|
|
|||
| if netrcFinder == nil { | |||
| netrcFinder = defaultNetrcFinder | |||
| } | |||
|
|
|||
| return &netrcCredentialHelper{netrcFinder: netrcFinder, skip: make(map[string]bool)} | |||
| } | |||
|
|
|||
| func (c *netrcCredentialHelper) Fill(what Creds) (Creds, error) { | |||
| host, err := getNetrcHostname(what["host"]) | |||
| if err != nil { | |||
| return nil, credHelperNoOp | |||
| } | |||
|
|
|||
| if c.skip[host] { | |||
| return nil, credHelperNoOp | |||
| } | |||
|
|
|||
| if machine := c.netrcFinder.FindMachine(host); machine != nil { | |||
| creds := make(Creds) | |||
| creds["username"] = machine.Login | |||
| creds["password"] = machine.Password | |||
| creds["protocol"] = what["protocol"] | |||
| creds["host"] = what["host"] | |||
| creds["scheme"] = what["scheme"] | |||
| creds["path"] = what["path"] | |||
| creds["source"] = "netrc" | |||
| tracerx.Printf("netrc: git credential fill (%q, %q, %q)", | |||
| what["protocol"], what["host"], what["path"]) | |||
| return creds, nil | |||
| } | |||
|
|
|||
| return nil, credHelperNoOp | |||
| } | |||
|
|
|||
| func getNetrcHostname(hostname string) (string, error) { | |||
| if strings.Contains(hostname, ":") { | |||
| host, _, err := net.SplitHostPort(hostname) | |||
| if err != nil { | |||
| tracerx.Printf("netrc: error parsing %q: %s", hostname, err) | |||
| return "", err | |||
| } | |||
| return host, nil | |||
| } | |||
|
|
|||
| return hostname, nil | |||
| } | |||
|
|
|||
| func (c *netrcCredentialHelper) Approve(what Creds) error { | |||
| if what["source"] == "netrc" { | |||
| host, err := getNetrcHostname(what["host"]) | |||
| if err != nil { | |||
| return credHelperNoOp | |||
| } | |||
| tracerx.Printf("netrc: git credential approve (%q, %q, %q)", | |||
| what["protocol"], what["host"], what["path"]) | |||
| c.skip[host] = false | |||
| return nil | |||
| } | |||
| return credHelperNoOp | |||
| } | |||
|
|
|||
| func (c *netrcCredentialHelper) Reject(what Creds) error { | |||
| if what["source"] == "netrc" { | |||
| host, err := getNetrcHostname(what["host"]) | |||
| if err != nil { | |||
| return credHelperNoOp | |||
| } | |||
|
|
|||
| tracerx.Printf("netrc: git credential reject (%q, %q, %q)", | |||
| what["protocol"], what["host"], what["path"]) | |||
| c.skip[host] = true | |||
| return nil | |||
| } | |||
| return credHelperNoOp | |||
| } | |||
| @@ -0,0 +1,82 @@ | |||
| package creds | |||
|
|
|||
| import ( | |||
| "strings" | |||
| "testing" | |||
|
|
|||
| "github.com/git-lfs/go-netrc/netrc" | |||
| ) | |||
|
|
|||
| func TestNetrcWithHostAndPort(t *testing.T) { | |||
| var netrcHelper netrcCredentialHelper | |||
| netrcHelper.netrcFinder = &fakeNetrc{} | |||
|
|
|||
| what := make(Creds) | |||
| what["protocol"] = "http" | |||
| what["host"] = "netrc-host:123" | |||
| what["path"] = "/foo/bar" | |||
|
|
|||
| creds, err := netrcHelper.Fill(what) | |||
| if err != nil { | |||
| t.Fatalf("error retrieving netrc credentials: %s", err) | |||
| } | |||
|
|
|||
| username := creds["username"] | |||
| if username != "abc" { | |||
| t.Fatalf("bad username: %s", username) | |||
| } | |||
|
|
|||
| password := creds["password"] | |||
| if password != "def" { | |||
| t.Fatalf("bad password: %s", password) | |||
| } | |||
| } | |||
|
|
|||
| func TestNetrcWithHost(t *testing.T) { | |||
| var netrcHelper netrcCredentialHelper | |||
| netrcHelper.netrcFinder = &fakeNetrc{} | |||
|
|
|||
| what := make(Creds) | |||
| what["protocol"] = "http" | |||
| what["host"] = "netrc-host" | |||
| what["path"] = "/foo/bar" | |||
|
|
|||
| creds, err := netrcHelper.Fill(what) | |||
| if err != nil { | |||
| t.Fatalf("error retrieving netrc credentials: %s", err) | |||
| } | |||
|
|
|||
| username := creds["username"] | |||
| if username != "abc" { | |||
| t.Fatalf("bad username: %s", username) | |||
| } | |||
|
|
|||
| password := creds["password"] | |||
| if password != "def" { | |||
| t.Fatalf("bad password: %s", password) | |||
| } | |||
| } | |||
|
|
|||
| func TestNetrcWithBadHost(t *testing.T) { | |||
| var netrcHelper netrcCredentialHelper | |||
| netrcHelper.netrcFinder = &fakeNetrc{} | |||
|
|
|||
| what := make(Creds) | |||
| what["protocol"] = "http" | |||
| what["host"] = "other-host" | |||
| what["path"] = "/foo/bar" | |||
|
|
|||
| _, err := netrcHelper.Fill(what) | |||
| if err != credHelperNoOp { | |||
| t.Fatalf("expected no-op for unknown host other-host") | |||
| } | |||
| } | |||
|
|
|||
| type fakeNetrc struct{} | |||
|
|
|||
| func (n *fakeNetrc) FindMachine(host string) *netrc.Machine { | |||
| if strings.Contains(host, "netrc") { | |||
| return &netrc.Machine{Login: "abc", Password: "def"} | |||
| } | |||
| return nil | |||
| } | |||
Oops, something went wrong.
0 comments on commit
1026ff0