Skip to content

Commit 9700105

Browse files
committed
fix: normalize client header parsing
1 parent 2a8b2b1 commit 9700105

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

app/main.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@
1616
F = TypeVar("F", bound=Callable[..., ResponseReturnValue])
1717

1818

19+
def _coerce_header(value: str | None) -> str:
20+
if value is None:
21+
return "unknown"
22+
cleaned = value.strip()
23+
return cleaned if cleaned else "unknown"
24+
25+
26+
def _normalize_cert_subject(value: str | None) -> str:
27+
subject = _coerce_header(value)
28+
if subject == "unknown":
29+
return subject
30+
prefix = "subject="
31+
if subject.lower().startswith(prefix):
32+
remainder = subject[len(prefix) :].lstrip()
33+
return remainder or "unknown"
34+
return subject
35+
36+
1937
def route(rule: str, **options: Any) -> Callable[[F], F]:
2038
return cast(Callable[[F], F], app.route(rule, **options))
2139

@@ -42,10 +60,8 @@ def health() -> Dict[str, str]:
4260
@route("/")
4361
def index() -> str:
4462
with record_route_metrics("index"):
45-
cert_subject = request.headers.get("X-Client-Subject", "unknown") or "unknown"
46-
if cert_subject.startswith("Subject="):
47-
cert_subject = cert_subject.replace("Subject=", "", 1)
48-
device_id = request.headers.get("X-Device-ID", "unknown") or "unknown"
63+
cert_subject = _normalize_cert_subject(request.headers.get("X-Client-Subject"))
64+
device_id = _coerce_header(request.headers.get("X-Device-ID"))
4965
return (
5066
f"Hello from keep protected app!\n"
5167
f"Client cert subject: {cert_subject}\n"

app/tests/test_main.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,24 @@ def test_empty_headers(client: TestClient) -> None:
127127
# Empty headers should fall back to "unknown"
128128
assert "Client cert subject: unknown" in text
129129
assert "Device ID: unknown" in text
130+
131+
132+
def test_headers_whitespace_only(client: TestClient) -> None:
133+
"""Whitespace-only headers should be treated as unknown."""
134+
headers = {"X-Client-Subject": " ", "X-Device-ID": " \t"}
135+
response = client.get("/", headers=headers)
136+
assert response.status_code == 200
137+
138+
text = response.get_data(as_text=True)
139+
assert "Client cert subject: unknown" in text
140+
assert "Device ID: unknown" in text
141+
142+
143+
def test_client_subject_case_insensitive_prefix(client: TestClient) -> None:
144+
"""Subject prefix removal should be case-insensitive and trim spacing."""
145+
headers = {"X-Client-Subject": "subject= [email protected]"}
146+
response = client.get("/", headers=headers)
147+
assert response.status_code == 200
148+
149+
text = response.get_data(as_text=True)
150+
assert "Client cert subject: [email protected]" in text

0 commit comments

Comments
 (0)