FIX: FinalDestination#get forwarding Authorization header on redirects (#27043)

This commits updates `FinalDestination#get` to not forward
`Authorization` header on redirects since most HTTP clients I tested like
curl and wget does not it.

This also fixes a recent problem in `DiscourseIpInfo.mmdb_download`
where we will fail to download the databases when both `GlobalSetting.maxmind_account_id` and
`GlobalSetting.maxmind_license_key` has been set. The failure is due to
the bug above where the redirected URL given by MaxMind does not accept
an `Authorization` header.
This commit is contained in:
Alan Guo Xiang Tan
2024-05-16 08:37:34 +08:00
committed by GitHub
parent 33871c4830
commit e31cf66f11
3 changed files with 47 additions and 11 deletions

View File

@ -156,7 +156,7 @@ class FinalDestination
# this is a new interface for simply getting
# N bytes accounting for all internal logic
def get(redirects = @limit, extra_headers: {}, &blk)
def get(redirects = @limit, extra_headers: {}, except_headers: [], &blk)
raise "Must specify block" unless block_given?
if @uri && @uri.port == 80 && FinalDestination.is_https_domain?(@uri.hostname)
@ -167,7 +167,7 @@ class FinalDestination
return if !validate_uri
return if @stop_at_blocked_pages && blocked_domain?(@uri)
result, headers_subset = safe_get(@uri, &blk)
result, headers_subset = safe_get(@uri, except_headers:, &blk)
return if !result
cookie = headers_subset.set_cookie
@ -198,7 +198,12 @@ class FinalDestination
extra = nil
extra = { "Cookie" => cookie } if cookie
get(redirects - 1, extra_headers: extra, &blk)
# Most HTTP Clients strip the Authorization header on redirects as the client could be redirecting to a untrusted
# party. Not stripping the Authorization header on redirect can also lead to problems where the
# redirected party does not expect a Authorization header and thus rejects the request.
except_headers = ["Authorization"]
get(redirects - 1, extra_headers: extra, except_headers:, &blk)
elsif result == :ok
@uri.to_s
else
@ -478,7 +483,7 @@ class FinalDestination
protected
def safe_get(uri)
def safe_get(uri, except_headers: [])
result = nil
unsafe_close = false
headers_subset = Struct.new(:location, :set_cookie).new
@ -488,7 +493,7 @@ class FinalDestination
request_headers.merge(
"Accept-Encoding" => "gzip",
"Host" => uri.hostname + (@include_port_in_host_header ? ":#{uri.port}" : ""),
)
).except(*except_headers)
req = FinalDestination::HTTP::Get.new(uri.request_uri, headers)