Skip to content

Commit 105f03b

Browse files
committed
fix: preserve auth header across multi-hop redirect chains
- Read Authorization from both headers and unredirected_hdrs in _StripAuthOnRedirect to survive multi-hop chains within allowed hosts - Add test_multi_hop_redirect_within_hosts_preserves_auth - 1832 tests passing
1 parent 3cd5541 commit 105f03b

2 files changed

Lines changed: 27 additions & 1 deletion

File tree

src/specify_cli/authentication/http.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ def __init__(self, hosts: tuple[str, ...]) -> None:
5454
self._hosts = hosts
5555

5656
def redirect_request(self, req, fp, code, msg, headers, newurl):
57-
original_auth = req.get_header("Authorization")
57+
original_auth = (
58+
req.get_header("Authorization")
59+
or req.unredirected_hdrs.get("Authorization")
60+
)
5861
new_req = super().redirect_request(req, fp, code, msg, headers, newurl)
5962
if new_req is not None:
6063
hostname = (urlparse(newurl).hostname or "").lower()

tests/test_authentication.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,29 @@ def test_redirect_outside_hosts_strips_auth(self):
686686
assert new_req.headers.get("Authorization") is None
687687
assert new_req.unredirected_hdrs.get("Authorization") is None
688688

689+
def test_multi_hop_redirect_within_hosts_preserves_auth(self):
690+
"""Auth survives a multi-hop redirect chain within allowed hosts."""
691+
from specify_cli.authentication.http import _StripAuthOnRedirect
692+
from urllib.request import Request
693+
import io
694+
hosts = ("github.com", "codeload.github.com", "objects-origin.githubusercontent.com")
695+
handler = _StripAuthOnRedirect(hosts)
696+
697+
# First hop: github.com → codeload.github.com
698+
req1 = Request("https://github.com/org/repo", headers={"Authorization": "Bearer tok"})
699+
req2 = handler.redirect_request(req1, io.BytesIO(b""), 302, "Found", {},
700+
"https://codeload.github.com/org/repo/zip")
701+
assert req2 is not None
702+
auth2 = req2.get_header("Authorization") or req2.unredirected_hdrs.get("Authorization")
703+
assert auth2 == "Bearer tok"
704+
705+
# Second hop: codeload.github.com → objects-origin.githubusercontent.com
706+
req3 = handler.redirect_request(req2, io.BytesIO(b""), 302, "Found", {},
707+
"https://objects-origin.githubusercontent.com/asset")
708+
assert req3 is not None
709+
auth3 = req3.get_header("Authorization") or req3.unredirected_hdrs.get("Authorization")
710+
assert auth3 == "Bearer tok"
711+
689712

690713
# ---------------------------------------------------------------------------
691714
# _fetch_latest_release_tag delegation

0 commit comments

Comments
 (0)