是否可以创建一个Git助手或插件来添加HTTP头或强制Bearer Token身份验证

tzdcorbm  于 2023-06-28  发布在  Git
关注(0)|答案(1)|浏览(180)

背景:我们使用Bitbucket服务器(即将升级/切换到Bitbucket数据中心)。在我们的身份验证设置中,我们禁用了用户密码(Web auth是通过不同的方式),因此对于Bitbucket/Git目的,我们使用Bitbucket个人访问令牌(PAT)。(SSH密钥身份验证在我们的组织中不是一个选项。)对于克隆/推送/等,我们一直在提示凭据时使用我们的用户名和PAT。这是可行的,但是由于我不能进入关于我们的身份验证设置的原因,它正在创建与我们的自动构建以及大型用户交互式本地构建相关的性能问题。
Bitbucket不使用HTTP(S)基本身份验证,还支持HTTP(S)Bearer令牌身份验证,您只需提供PAT而无需用户名。这样做可以解决我们的性能问题。在REST API请求上这样做很容易。在Git上这样做更棘手。This Bitbucket documentation建议这样做:

$ git clone -c http.extraHeader='Authorization: Bearer xxxx' https://bitbucketserver.com/scm/projectname/teamsinspace.git

这是有效的!但是它通过命令历史等向其他人公开PAT。不暴露PAT的更安全的变体也可以工作:

$ git clone --config-env=http.extraHeader=GIT_AUTHORIZATION_HEADER https://bitbucketserver.com/scm/projectname/teamsinspace.git

其中GIT_AUTHORIZATION_HEADERAuthorization: Bearer xxxx。但这仍然有一些缺点,即它不能使用.gitconfig,并且必须添加到每个命令中,并且用户必须提前配置,并且不能提示输入安全存储在Git凭据助手中的PAT。
GitLab提供了一个“魔术用户名”OAuth2,可以通过基本身份验证与令牌一起提供,基本身份验证基本上告诉服务器“忽略用户名,仅使用令牌进行身份验证”。Bitbucket also provides类似的“魔术用户名”x-token-auth,但它似乎是仅限云或仅限于存储库访问令牌或两者兼而有之,因为我们已经尝试使用它,它只会导致身份验证错误。访问这样的功能将允许我们在.gitconfig中硬编码魔术用户名,开发人员只会得到提示“www.example.com的密码x-token-auth@our-server.com”,这将是PAT。但是,唉,我们不能使用这个功能。
大约14年前,在Git邮件列表上有一个关于支持Bearer令牌认证的讨论,甚至提出了一个补丁,但看起来它没有去任何地方。理论上,我可以应用该补丁的现代化版本并重新编译Git,但这对我们的开发人员组织来说真的不是一个理想的解决方案。
我曾经考虑过创建一个Git credential helper(实际上我之前也因为其他原因创建过)和一个Git host provider,但是所有与凭证相关的东西都被硬编码到了用户名/密码中,所以这些都不起作用。
因此,我正在寻找/希望的是某种方法来创建某种类型的帮助程序,提供程序或插件,这些帮助程序,提供程序或插件将能够指定,覆盖或替换HTTP Authorization头,使其成为Bearer而不是Basic,无论是使用来自内置Git凭据的密码,还是在必要时提示新的东西,而不必编译我们自己的自定义Git fork。这完全可能吗?或者我应该给予并使用--config-env

ttcibm8c

ttcibm8c1#

绝对不会为此感到自豪,但不得不在CI环境中求助于一些肮脏的东西,也是因为“原因”...
这两种解决方案都不是理想的,但最简单的方法是在gitconfig中创建一个shell别名,并添加到从stdin读取令牌的.bashrc/.zshrc中

## example that shows header is set correctly but does not show up actual value in command line history  
## replace `whoami` command with command/script to retrieve token
$ GIT_CURL_VERBOSE=1 git -c http.extraHeader="Hello: $(whoami)" ls-remote https://github.com/deric4/github-action-runner-reference
...
15:43:52.454783 http.c:701              == Info: using HTTP/2
15:43:52.454838 http.c:701              == Info: h2h3 [:method: GET]
15:43:52.454844 http.c:701              == Info: h2h3 [:path: /deric4/github-action-runner-reference/info/refs?service=git-upload-pack]
15:43:52.454849 http.c:701              == Info: h2h3 [:scheme: https]
15:43:52.454853 http.c:701              == Info: h2h3 [:authority: github.com]
15:43:52.454857 http.c:701              == Info: h2h3 [user-agent: git/2.39.2 (Apple Git-143)]
15:43:52.454861 http.c:701              == Info: h2h3 [accept: */*]
15:43:52.454865 http.c:701              == Info: h2h3 [accept-encoding: deflate, gzip]
15:43:52.454869 http.c:701              == Info: h2h3 [hello: deric4]
15:43:52.454873 http.c:701              == Info: h2h3 [pragma: no-cache]
15:43:52.454876 http.c:701              == Info: h2h3 [git-protocol: version=2]
...
# .gitconfig
[alias]
    myalias = "!f() { GIT_CURL_VERBOSE=1 git -c http.extraHeader=\"Hello: $(whoami)\" ls-remote $1 ; }; f"

一种更激进的方法是实现自定义的remote helper来添加/代替凭证助手。
我能够挖掘出一个我并不引以为傲但却完成了任务的老例子:
这将允许基于执行上下文动态地获取和设置配置/凭证。
git clone accesstoken://some-profile@foo-bar-baz

// Note: that this was written in go 1.12 and hadn't looked at it since then so...
func main() {

    remoteName := os.Args[1]
    repoUrl := os.Args[2]

    u, err := url.Parse(repoUrl)
    if err != nil {
        log.Fatal(err)
    }
    
    // replaced complex steps to just getting the env var
    accessToken := os.Getenv("GIT_ACCESS_TOKEN")

    // get username so it can be reset when password is added
    username := u.User.Username()

    // construct <username>:<password>
    u.User = url.UserPassword(username, accessToken)

    // convert from accesstoken -> https
    u.Scheme = "https"

    cmd := exec.Command("git", "remote-http", remoteName, u.String())
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Stdin = os.Stdin

    err = cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
}

但你的情况是

// custom logic to get bearer token
    
    cmd := exec.Command("git", "-c", "http.extraHeader='Bearer: <token from somewhere>'", "remote-http", remoteName, u.String())

相关问题