From: "Matthew John Cheetham via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, johannes.schindelin@gmx.de,
Matthew John Cheetham <mjcheetham@outlook.com>,
Matthew John Cheetham <mjcheetham@outlook.com>
Subject: [PATCH 2/3] http: attempt Negotiate auth in http.emptyAuth=auto mode
Date: Thu, 16 Apr 2026 09:20:58 +0000 [thread overview]
Message-ID: <f175294459c9370ed79c8338d6008b69c2028f99.1776331259.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2087.git.1776331259.gitgitgadget@gmail.com>
From: Matthew John Cheetham <mjcheetham@outlook.com>
When a server advertises Negotiate (SPNEGO) authentication, the
"auto" mode of http.emptyAuth should detect this as an "exotic"
method and proactively send empty credentials, allowing libcurl to
use the system Kerberos ticket without prompting the user.
However, two features interact to prevent this from working:
The Negotiate-stripping logic, introduced in 4dbe66464b
(remote-curl: fall back to Basic auth if Negotiate fails,
2015-01-08), removes CURLAUTH_GSSNEGOTIATE from the allowed
methods on the first 401 response. The empty-auth auto-detection,
introduced in 40a18fc77c (http: add an "auto" mode for
http.emptyauth, 2017-02-25), then checks the remaining methods
for anything "exotic" -- but Negotiate has already been removed,
so auto mode never activates for servers whose only non-Basic/Digest
method is Negotiate (e.g., Apache with mod_auth_kerb offering
Basic + Negotiate).
Fix this by delaying the Negotiate stripping in auto mode: on the
first 401, keep Negotiate in the allowed methods so that auto mode
can detect it and retry with empty credentials. If that attempt
fails (no valid Kerberos ticket), strip Negotiate on the second 401
and fall through to credential_fill() as usual.
To support this, also teach http_reauth_prepare() to skip
credential_fill() when empty auth is about to be attempted, since
filling real credentials would bypass the empty-auth mechanism.
The true and false modes are unchanged: true sends empty credentials
on the very first request (before any 401), and false never sends
them.
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
---
http.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/http.c b/http.c
index f208e0ad82..1c7ea32ef2 100644
--- a/http.c
+++ b/http.c
@@ -138,6 +138,7 @@ static unsigned long empty_auth_useless =
CURLAUTH_BASIC
| CURLAUTH_DIGEST_IE
| CURLAUTH_DIGEST;
+static int empty_auth_try_negotiate;
static struct curl_slist *pragma_header;
static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
@@ -667,6 +668,17 @@ static void init_curl_http_auth(CURL *result)
void http_reauth_prepare(int all_capabilities)
{
+ /*
+ * If we deferred stripping Negotiate to give empty auth a
+ * chance (auto mode), skip credential_fill on this retry so
+ * that init_curl_http_auth() sends empty credentials and
+ * libcurl can attempt Negotiate with the system ticket cache.
+ */
+ if (empty_auth_try_negotiate &&
+ !http_auth.password && !http_auth.credential &&
+ (http_auth_methods & CURLAUTH_GSSNEGOTIATE))
+ return;
+
credential_fill(the_repository, &http_auth, all_capabilities);
}
@@ -1895,7 +1907,18 @@ static int handle_curl_result(struct slot_results *results)
http_proactive_auth = PROACTIVE_AUTH_NONE;
return HTTP_NOAUTH;
} else {
- http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
+ if (curl_empty_auth == -1 &&
+ !empty_auth_try_negotiate &&
+ (results->auth_avail & CURLAUTH_GSSNEGOTIATE)) {
+ /*
+ * In auto mode, give Negotiate a chance via
+ * empty auth before stripping it. If it fails,
+ * we will strip it on the next 401.
+ */
+ empty_auth_try_negotiate = 1;
+ } else {
+ http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
+ }
if (results->auth_avail) {
http_auth_methods &= results->auth_avail;
http_auth_methods_restricted = 1;
--
gitgitgadget
next prev parent reply other threads:[~2026-04-16 9:21 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-16 9:20 [PATCH 0/3] http: fix emptyAuth=auto for Negotiate/SPNEGO Matthew John Cheetham via GitGitGadget
2026-04-16 9:20 ` [PATCH 1/3] http: extract http_reauth_prepare() from retry paths Matthew John Cheetham via GitGitGadget
2026-04-16 16:21 ` Junio C Hamano
2026-04-16 9:20 ` Matthew John Cheetham via GitGitGadget [this message]
2026-04-16 16:40 ` [PATCH 2/3] http: attempt Negotiate auth in http.emptyAuth=auto mode Junio C Hamano
2026-04-28 14:38 ` Matthew John Cheetham
[not found] ` <xmqqse8dz4pi.fsf@gitster.g>
2026-04-30 10:53 ` Matthew John Cheetham
2026-04-16 9:20 ` [PATCH 3/3] t5563: add tests for http.emptyAuth with Negotiate Matthew John Cheetham via GitGitGadget
2026-04-30 10:54 ` [PATCH v2 0/4] http: fix emptyAuth=auto for Negotiate/SPNEGO Matthew John Cheetham via GitGitGadget
2026-04-30 10:54 ` [PATCH v2 1/4] http: extract http_reauth_prepare() from retry paths Matthew John Cheetham via GitGitGadget
2026-04-30 10:54 ` [PATCH v2 2/4] http: attempt Negotiate auth in http.emptyAuth=auto mode Matthew John Cheetham via GitGitGadget
2026-04-30 10:54 ` [PATCH v2 3/4] t5563: add tests for http.emptyAuth with Negotiate Matthew John Cheetham via GitGitGadget
2026-04-30 10:54 ` [PATCH v2 4/4] doc: clarify http.emptyAuth values Matthew John Cheetham via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f175294459c9370ed79c8338d6008b69c2028f99.1776331259.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=johannes.schindelin@gmx.de \
--cc=mjcheetham@outlook.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox