Skip to content

Commit 5ce7010

Browse files
fix: match complete www-authenticate auth params
1 parent 220d362 commit 5ce7010

2 files changed

Lines changed: 29 additions & 2 deletions

File tree

src/mcp/client/auth/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ def extract_field_from_www_auth(response: Response, field_name: str) -> str | No
2626
if not www_auth_header:
2727
return None
2828

29-
# Pattern matches: field_name="value" or field_name=value (unquoted)
30-
pattern = rf'{field_name}=(?:"([^"]+)"|([^\s,]+))'
29+
# Pattern matches complete auth-param names: field_name="value" or field_name=value (unquoted).
30+
field_pattern = re.escape(field_name)
31+
pattern = rf'(?:^|[\s,]){field_pattern}=(?:"([^"]+)"|([^\s,]+))'
3132
match = re.search(pattern, www_auth_header)
3233

3334
if match:

tests/client/test_auth.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,6 +2005,14 @@ class TestWWWAuthenticate:
20052005
),
20062006
# Multiple parameters with unquoted value
20072007
('Bearer realm="api", scope=basic', "scope", "basic"),
2008+
# Decoy parameter name before the real field
2009+
('Bearer error_scope="decoy", scope="read write"', "scope", "read write"),
2010+
(
2011+
'Bearer x_resource_metadata="https://decoy.example.com", '
2012+
'resource_metadata="https://api.example.com/.well-known/oauth-protected-resource"',
2013+
"resource_metadata",
2014+
"https://api.example.com/.well-known/oauth-protected-resource",
2015+
),
20082016
# Values with special characters
20092017
(
20102018
'Bearer scope="resource:read resource:write user_profile"',
@@ -2047,6 +2055,12 @@ def test_extract_field_from_www_auth_valid_cases(
20472055
# Header without requested field
20482056
('Bearer realm="api", error="insufficient_scope"', "scope", "no scope parameter"),
20492057
('Bearer realm="api", scope="read write"', "resource_metadata", "no resource_metadata parameter"),
2058+
('Bearer custom_scope="leaked"', "scope", "substring param name should not match scope"),
2059+
(
2060+
'Bearer x_resource_metadata="https://decoy.example.com"',
2061+
"resource_metadata",
2062+
"substring param name should not match resource_metadata",
2063+
),
20502064
# Malformed field (empty value)
20512065
("Bearer scope=", "scope", "malformed scope parameter"),
20522066
("Bearer resource_metadata=", "resource_metadata", "malformed resource_metadata parameter"),
@@ -2070,6 +2084,18 @@ def test_extract_field_from_www_auth_invalid_cases(
20702084
result = extract_field_from_www_auth(init_response, field_name)
20712085
assert result is None, f"Should return None for {description}"
20722086

2087+
def test_extract_resource_metadata_from_www_auth_ignores_substring_param_name(self):
2088+
"""Test resource_metadata extraction ignores auth-params with longer names."""
2089+
init_response = httpx.Response(
2090+
status_code=401,
2091+
headers={"WWW-Authenticate": 'Bearer x_resource_metadata="https://decoy.example.com"'},
2092+
request=httpx.Request("GET", "https://api.example.com/test"),
2093+
)
2094+
2095+
result = extract_resource_metadata_from_www_auth(init_response)
2096+
2097+
assert result is None
2098+
20732099

20742100
class TestCIMD:
20752101
"""Test Client ID Metadata Document (CIMD) support."""

0 commit comments

Comments
 (0)