From 0fdc71db4e5063bd7f96d7d379c608eebabde690 Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Thu, 10 Aug 2017 16:30:42 -0600 Subject: [PATCH] lfsapi/creds: use AskPassCredentialHelper with GIT_ASKPASS --- docs/man/git-lfs-config.5.ronn | 6 +++++ lfsapi/creds.go | 31 ++++++++++++++++++++- test/test-askpass.sh | 49 ++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100755 test/test-askpass.sh diff --git a/docs/man/git-lfs-config.5.ronn b/docs/man/git-lfs-config.5.ronn index 099692ce..cb37adda 100644 --- a/docs/man/git-lfs-config.5.ronn +++ b/docs/man/git-lfs-config.5.ronn @@ -51,6 +51,12 @@ be scoped inside the configuration for a remote. Sets the maximum time, in seconds, for the HTTP client to maintain keepalive connections. Default: 30 minutes. +* `core.askpass`, GIT_ASKPASS + + Given as a program and its arguments, this is invoked when authentication is + needed against the LFS API. The contents of stdout are interpreted as the + password. + * `lfs.cachecredentials` Enables in-memory SSH and Git Credential caching for a single 'git lfs' diff --git a/lfsapi/creds.go b/lfsapi/creds.go index d6ddc767..f80d3c34 100644 --- a/lfsapi/creds.go +++ b/lfsapi/creds.go @@ -9,12 +9,19 @@ import ( "github.com/git-lfs/git-lfs/config" "github.com/git-lfs/git-lfs/errors" + "github.com/git-lfs/git-lfs/tools" "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"` // Cached is a boolean determining whether or not to enable the // credential cacher. Cached bool `git:"lfs.cachecredentials"` @@ -34,6 +41,21 @@ func getCredentialHelper(cfg *config.Configuration) (CredentialHelper, error) { return nil, err } + var hs []CredentialHelper + if len(ccfg.AskPass) > 0 { + parts := tools.QuotedFields(ccfg.AskPass) + if len(parts) < 1 { + return nil, errors.Errorf( + "lfsapi/creds: invalid ASKPASS: %q", + ccfg.AskPass) + } + + hs = append(hs, &AskPassCredentialHelper{ + Program: parts[0], + Args: parts[1:], + }) + } + var h CredentialHelper h = &commandCredentialHelper{ SkipPrompt: ccfg.SkipPrompt, @@ -42,8 +64,15 @@ func getCredentialHelper(cfg *config.Configuration) (CredentialHelper, error) { if ccfg.Cached { h = withCredentialCache(h) } + hs = append(hs, h) - return h, nil + switch len(hs) { + case 0: + return nil, nil + case 1: + return hs[0], nil + } + return CredentialHelpers(hs), nil } // getCredentialConfig parses a *credsConfig given the OS and Git diff --git a/test/test-askpass.sh b/test/test-askpass.sh new file mode 100755 index 00000000..a056b84f --- /dev/null +++ b/test/test-askpass.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +. "test/testlib.sh" + +begin_test "askpass: push with GIT_ASKPASS" +( + set -e + + reponame="askpass-with-environ" + setup_remote_repo "$reponame" + clone_repo "$reponame" "$reponame" + + git lfs track "*.dat" + echo "hello" > a.dat + + git add .gitattributes a.dat + git commit -m "initial commit" + + # $password is defined from test/cmd/lfstest-gitserver.go (see: skipIfBadAuth) + password="pass" + GIT_ASKPASS="echo $password" GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push 2>&1 | tee push.log + + grep "filling with GIT_ASKPASS: echo $password" push.log +) +end_test + +begin_test "askpass: push with core.askpass" +( + set -e + + reponame="askpass-with-config" + setup_remote_repo "$reponame" + clone_repo "$reponame" "$reponame" + + git lfs track "*.dat" + echo "hello" > a.dat + + git add .gitattributes a.dat + git commit -m "initial commit" + + # $password is defined from test/cmd/lfstest-gitserver.go (see: skipIfBadAuth) + password="pass" + git config "core.askpass" "echo $password" + cat .git/config + GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push 2>&1 | tee push.log + + grep "filling with GIT_ASKPASS: echo $password" push.log +) +end_test