From: Aaron Plattner <aplattner@nvidia.com>
To: <git@vger.kernel.org>
Cc: Aaron Plattner <aplattner@nvidia.com>,
Rahul Rameshbabu <rrameshbabu@nvidia.com>
Subject: [PATCH] http: preserve wwwauth_headers across redirects
Date: Tue, 2 Jun 2026 09:11:48 -0700 [thread overview]
Message-ID: <20260602161150.1527493-1-aplattner@nvidia.com> (raw)
When cURL follows a redirect, it calls the CURLOPT_HEADERFUNCTION for
each header received including ones from a redirect. http_request() sets
fwrite_wwwauth() as the header function, which will record the wwwauth[]
entries for the last step in the redirection chain.
However, when http_request_recoverable() sees that cURL followed a
redirect, it attempts to update the credentials for the request from the
new URL using credential_from_url(). The first thing that does is call
credential_clear(), which clears everything including wwwauth_headers.
If the new URL should use a credential helper rather than credentials
embedded in the URL, this loses the list of authentication methods that
the server provided in the redirect.
For example, I have a server that supports HTTP but always redirects to
HTTPS before handling requests. This redirect breaks OAuth
authentication:
$ git ls-remote http://server/git
=> Send header: GET /git/info/refs?service=git-upload-pack HTTP/1.1
<= Recv header: HTTP/1.1 302 Found
<= Recv header: Location: https://server.nvidia.com/git/info/refs?service=git-upload-pack
== Info: Issue another request to this URL: 'https://server.nvidia.com/git/info/refs?service=git-upload-pack'
=> Send header: GET /git/info/refs?service=git-upload-pack HTTP/1.1
<= Recv header: HTTP/1.1 401 Unauthorized
<= Recv header: WWW-Authenticate: Bearer error="invalid_request", error_description="No bearer token found in the request", msal-tenant-id="<tenant>", msal-client-id="<client>"
trace: run_command: 'git credential-cache --timeout 7200 get'
trace: start_command: /bin/sh -c 'git credential-cache --timeout 7200 get' 'git credential-cache --timeout 7200 get'
trace: built-in: git credential-cache --timeout 7200 get
trace: run_command: 'git credential-msal get'
trace: start_command: /bin/sh -c 'git credential-msal get' 'git credential-msal get'
trace: exec: git-credential-msal get
trace: run_command: git-credential-msal get
trace: start_command: /usr/bin/git-credential-msal get
Username for 'https://server.nvidia.com': ^C
When git invokes the credential helper, it doesn't include the wwwauth[]
array, so git-credential-msal doesn't think that OAuth is supported [1].
Fix the problem by preserving the wwwauth_headers strvec across the call
to credential_from_url().
[1] https://github.com/Binary-Eater/git-credential-msal/blob/trunk/src/git_credential_msal/main.py#L69
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
---
http.c | 14 ++++++++++++
t/lib-httpd/apache.conf | 1 +
t/t5563-simple-http-auth.sh | 45 +++++++++++++++++++++++++++++++++++++
3 files changed, 60 insertions(+)
diff --git a/http.c b/http.c
index ea9b16861b..cac8c9bfc9 100644
--- a/http.c
+++ b/http.c
@@ -2425,7 +2425,21 @@ static int http_request_recoverable(const char *url,
if (options->effective_url && options->base_url) {
if (update_url_from_redirect(options->base_url,
url, options->effective_url)) {
+ struct strvec wwwauth_headers = STRVEC_INIT;
+
+ /*
+ * Preserve wwwauth_headers across the call to
+ * credential_from_url(): if the effective URL doesn't
+ * specify its own credentials, a credential helper
+ * might need the wwwauth[] array from the server's
+ * redirect response in order to authenticate.
+ */
+ strvec_pushv(&wwwauth_headers,
+ http_auth.wwwauth_headers.v);
credential_from_url(&http_auth, options->base_url->buf);
+ strvec_pushv(&http_auth.wwwauth_headers,
+ wwwauth_headers.v);
+ strvec_clear(&wwwauth_headers);
url = options->effective_url->buf;
}
}
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 40a690b0bb..664f23fc6c 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -202,6 +202,7 @@ RewriteRule ^/dumb-redir/(.*)$ /dumb/$1 [R=301]
RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301]
RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302]
RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301]
+RewriteRule ^/custom_auth_redir/(.*)$ /custom_auth/$1 [R=302]
RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301]
RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh
index a7d475dd68..349ae4ab39 100755
--- a/t/t5563-simple-http-auth.sh
+++ b/t/t5563-simple-http-auth.sh
@@ -557,6 +557,51 @@ test_expect_success 'access using bearer auth' '
EOF
'
+test_expect_success 'bearer auth after redirect preserves wwwauth headers' '
+ test_when_finished "per_test_cleanup" &&
+
+ set_credential_reply get <<-EOF &&
+ capability[]=authtype
+ authtype=Bearer
+ credential=YS1naXQtdG9rZW4=
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.valid" <<-EOF &&
+ id=1 creds=Bearer YS1naXQtdG9rZW4=
+ EOF
+
+ cat >"$HTTPD_ROOT_PATH/custom-auth.challenge" <<-EOF &&
+ id=1 status=200
+ id=default response=WWW-Authenticate: FooBar param1="value1" param2="value2"
+ id=default response=WWW-Authenticate: Bearer authorize_uri="id.example.com" p=1 q=0
+ id=default response=WWW-Authenticate: Basic realm="example.com"
+ EOF
+
+ test_config_global credential.helper test-helper &&
+ test_config_global credential.useHttpPath true &&
+ git ls-remote "$HTTPD_URL/custom_auth_redir/repo.git" &&
+
+ expect_credential_query get <<-EOF &&
+ capability[]=authtype
+ capability[]=state
+ protocol=http
+ host=$HTTPD_DEST
+ path=custom_auth/repo.git
+ wwwauth[]=FooBar param1="value1" param2="value2"
+ wwwauth[]=Bearer authorize_uri="id.example.com" p=1 q=0
+ wwwauth[]=Basic realm="example.com"
+ EOF
+
+ expect_credential_query store <<-EOF
+ capability[]=authtype
+ authtype=Bearer
+ credential=YS1naXQtdG9rZW4=
+ protocol=http
+ host=$HTTPD_DEST
+ path=custom_auth/repo.git
+ EOF
+'
+
test_expect_success 'access using bearer auth with invalid credentials' '
test_when_finished "per_test_cleanup" &&
--
2.54.0
next reply other threads:[~2026-06-02 16:12 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-02 16:11 Aaron Plattner [this message]
2026-06-03 0:15 ` [PATCH] http: preserve wwwauth_headers across redirects Junio C Hamano
2026-06-03 0:37 ` Aaron Plattner
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=20260602161150.1527493-1-aplattner@nvidia.com \
--to=aplattner@nvidia.com \
--cc=git@vger.kernel.org \
--cc=rrameshbabu@nvidia.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