如何强制 Git (2.5+) HTTP 传输更喜欢 SPNEGO 而不是基本身份验证?

How to force Git (2.5+) HTTP transport prefer SPNEGO over Basic authentication?

总结: 我正在使用 Git for Windows 2.5.1 通过 Kerbesized Git 服务器进行身份验证。当我使用 https://el2-gitlab.sa.c/kkm/GrammarTools.git 形式的 URL 时,Git 甚至没有尝试协商身份验证,而是要求输入用户名和密码。强制 Git 使用 SPNEGO 的解决方法是 provide empty username and password in the URL itself,如 https://:@el2-gitlab.sa.c/kkm/GrammarTools.git。在这种情况下,Git 愉快地使用现有的 Kerberos 票证进行身份验证。

我可以配置 Git 来尝试 SPNEGO 而无需调整遥控器 URL 吗?

更多细节。我花了很多时间试图解决这个问题。首先我尝试了 giving an empty user name in .gitconfig,但没有成功:

[credential "https://el2-gitlab.sa.c"]
   username = ''

我没有一次遇到过关于 reverse 问题的问题,当时 Git 在尝试协商失败后拒绝恢复到 Basic,但行为是 confirmed to have changed in 2.3.1.

用空的用户名和密码响应提示没有帮助,这与我在 SO 上找到的一些建议相反(但它们可能早于版本 2.3.1)。

最后,详细的 libcurl 输出(此处删节)表明 Git 确实尝试了基本身份验证并完全放弃了协商:

$ export GIT_CURL_VERBOSE=1
$ git clone https://el2-gitlab.sa.c/kkm/GrammarTools.git kerbtest
Cloning into 'kerbtest'...
* Couldn't find host el2-gitlab.sa.c in the _netrc file; using defaults
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
> GET /kkm/GrammarTools.git/info/refs?service=git-upload-pack HTTP/1.1
Host: el2-gitlab.sa.c
User-Agent: git/2.5.1.windows.1

< HTTP/1.1 401 Unauthorized
< Status: 401 Unauthorized
< Www-Authenticate: Basic realm=""
< Www-Authenticate: Negotiate
<
* Connection #0 to host el2-gitlab.sa.c left intact
Username for 'https://el2-gitlab.sa.c':

另外可能感兴趣的是 Git 客户端在使用票证响应之前第二次重试 401 上的未经身份验证的请求:

$ git clone https://:@el2-gitlab.sa.c/kkm/GrammarTools.git kerbtest
Cloning into 'kerbtest'...
* Couldn't find host el2-gitlab.sa.c in the _netrc file; using defaults
> GET /kkm/GrammarTools.git/info/refs?service=git-upload-pack HTTP/1.1
Host: el2-gitlab.sa.c
User-Agent: git/2.5.1.windows.1

< HTTP/1.1 401 Unauthorized
< Status: 401 Unauthorized
< Www-Authenticate: Basic realm=""
< Www-Authenticate: Negotiate
* Connection #0 to host el2-gitlab.sa.c left intact
* Issue another request to this URL: 'https://:@el2-gitlab.sa.c/kkm/GrammarTools.git/info/refs?service=git-upload-pack'
* Couldn't find host el2-gitlab.sa.c in the _netrc file; using defaults
> GET /kkm/GrammarTools.git/info/refs?service=git-upload-pack HTTP/1.1
Host: el2-gitlab.sa.c
User-Agent: git/2.5.1.windows.1

< HTTP/1.1 401 Unauthorized
< Status: 401 Unauthorized
< Www-Authenticate: Basic realm=""
< Www-Authenticate: Negotiate
<
* Issue another request to this URL: 'https://:@el2-gitlab.sa.c/kkm/GrammarTools.git/info/refs?service=git-upload-pack'
* Couldn't find host el2-gitlab.sa.c in the _netrc file; using defaults
> GET /kkm/GrammarTools.git/info/refs?service=git-upload-pack HTTP/1.1
Host: el2-gitlab.sa.c
Authorization: Negotiate YIIGtg[ .... trimmed ... ]
User-Agent: git/2.5.1.windows.1

< HTTP/1.1 200 OK

这不是 Git 问题,而是 curl 问题。您正在遭受 known bug #10 的困扰。 curl 的实现远低于 Subversion 中使用的 libserf

关于 selectauth 的离子:Git 请求 ANY_AUTH libcurl 并且它应该 select 最强大的可用机制。如果没有(使用普通 curl),则您发现了一个错误。请在 GitHub.

上向 curl 报告

注意: 这曾经是选定的答案,但从 git v2.8 开始已过时。请滚动到 ,现在已勾选绿色。

这条线以下的所有内容都是历史性的和过时的。不要。


鉴于大多数 在他对这个问题的回答下的讨论,我相信为了 SO 社区的利益,应该发布问题的最终直接解决方案。

Michael 提到的 libcurl 中已知错误的解决方法是创建一个文件 ~/.netrc(原始 libcurl)或 ~/_netrc(Git for Windows 2.5+端口,基于 MSys2)。该文件应该为 Kerberized Git 服务器主机提供一个空的用户名和密码。由于主机匹配是精确的,因此包括短的和完全限定的 DNS 名称以及可能的别名(如果有的话),例如,

machine gitlab.acme.com username '' password ''
machine gitlab          username '' password ''

如果一切正确,您在原始问题日志中看到的行

* Couldn't find host el2-gitlab.sa.c in the _netrc file; using defaults

不应再打印,应使用带有用户 Kerberos 票证的协商身份验证。

git 2.8(2016 年 3 月)应该可以缓解这个问题,在 http 身份验证期间强制使用空的用户名和密码

参见 commit 121061f (15 Feb 2016) by brian m. carlson (bk2204)
(由 Junio C Hamano -- gitster -- in commit 65ba75b 合并,2016 年 2 月 24 日)

http: add option to try authentication without username

Performing GSS-Negotiate authentication using Kerberos does not require specifying a username or password, since that information is already included in the ticket itself.
However, libcurl refuses to perform authentication if it has not been provided with a username and password.

Add an option, http.emptyAuth, that provides libcurl with an empty username and password to make it attempt authentication anyway.

git config documentation会提到:

http.emptyAuth:

Attempt authentication without seeking a username or password.
This can be used to attempt GSS-Negotiate authentication without specifying a username in the URL, as libcurl normally requires a username for authentication.


Git 2.10.2(2016 年 10 月)将对此进行改进。

参见 commit 5275c30 (04 Oct 2016) by David Turner (csusbdt)
(由 Junio C Hamano -- gitster -- in commit c6400bf 合并,2016 年 10 月 17 日)

http: http.emptyauth should allow empty (not just NULL) usernames

When using Kerberos authentication with newer versions of libcurl, CURLOPT_USERPWD must be set to a value, even if it is an empty value. The value is never sent to the server.
Previous versions of libcurl did not require this variable to be set.
One way that some users express the empty username/password is http://:@gitserver.example.com, which http.emptyauth was designed to support.
Another, equivalent, URL is http://@gitserver.example.com.
The latter leads to a username of zero-length, rather than a NULL username, but CURLOPT_USERPWD still needs to be set (if http.emptyauth is set).
Do so.


Git 2.13(2017 年第 2 季度)将在服务器仅支持单一身份验证方法时减少通过 HTTP 的身份验证往返。

参见 commit 40a18fc (25 Feb 2017), and commit 840398f (22 Feb 2017) by Jeff King (peff)
帮助:Johannes Schindelin (dscho).
(由 Junio C Hamano -- gitster -- in commit 92718f5 合并,2017 年 3 月 10 日)

http: add an "auto" mode for http.emptyauth

This variable (http.emptyauth) needs to be specified to make some types of non-basic authentication work, but ideally this would just work out of the box for everyone.

However, simply setting it to "1" by default introduces an extra round-trip for cases where it isn't useful. We end up sending a bogus empty credential that the server rejects.

The "auto" mode should make it work out of the box, without incurring any extra round-trips for people hitting Basic-only servers.