Skip to content

Commit 2e8ffc6

Browse files
hsbtclaude
andcommitted
Keep credentials on same-host absolute redirects of the compact index
`uri + location` drops the userinfo when Location is an absolute URL, so a private index redirecting to another path on the same host lost the credentials and the follow-up request failed authentication. Bundler's downloader already re-applies them; cross-host redirects still drop them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 96bcc78 commit 2e8ffc6

2 files changed

Lines changed: 14 additions & 0 deletions

File tree

lib/rubygems/compact_index_client/http_fetcher.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ def fetch(uri, headers, redirects_remaining)
4848
if https?(uri) && !https?(redirect)
4949
raise Gem::RemoteFetcher::FetchError.new("redirecting to non-https resource: #{Gem::Uri.redact(redirect)}", uri)
5050
end
51+
# An absolute Location on the same host drops the credentials that a
52+
# relative one would have kept.
53+
redirect.userinfo = uri.userinfo if redirect.host == uri.host && !redirect.userinfo
5154

5255
fetch(redirect, headers, redirects_remaining - 1)
5356
when Gem::Net::HTTPRangeNotSatisfiable

test/rubygems/test_gem_compact_index_client_http_fetcher.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,17 @@ def test_call_keeps_credentials_on_an_accepted_redirect
230230
assert_equal "s3cr3t", remote.requests.last.first.password
231231
end
232232

233+
def test_call_keeps_credentials_on_an_absolute_same_host_redirect
234+
remote = FakeRemoteFetcher.new(
235+
"https://user:s3cr3t@index.example/versions" => FakeRedirect.new("https://index.example/v2/versions"),
236+
"https://user:s3cr3t@index.example/v2/versions" => FakeResponse.new("data")
237+
)
238+
fetcher = Gem::CompactIndexClient::HTTPFetcher.new("https://user:s3cr3t@index.example", remote)
239+
240+
assert_equal "data", fetcher.call("versions").body
241+
assert_equal "s3cr3t", remote.requests.last.first.password
242+
end
243+
233244
def test_call_drops_credentials_on_a_cross_host_redirect
234245
remote = FakeRemoteFetcher.new(
235246
"https://user:s3cr3t@index.example/versions" => FakeRedirect.new("https://mirror.example/versions"),

0 commit comments

Comments
 (0)