test(auth): cover userinfo SSRF scheme guard; note empty-scope caveat
Address claude-review round 7 nits on #919: - Add test_validate_via_userinfo_rejects_non_http_scheme — a non-http(s) userinfo_uri is refused before any request (covers the SSRF scheme guard). - Docstring caution on _validate_via_userinfo: userinfo-validated tokens carry empty scopes, so management endpoints must not gate on scopes for this path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
bc6595b139
commit
a53e6e7721
@@ -640,6 +640,11 @@ class UnifiedTokenVerifier(TokenVerifier):
|
||||
management-API allowlist is relaxed for it (authorization is still
|
||||
enforced per-user by every management endpoint).
|
||||
|
||||
Caution: userinfo-validated tokens carry **empty scopes**. Callers must
|
||||
not gate management endpoints on scopes for this path (e.g. a future
|
||||
``@require_scopes``) or they would silently reject valid cross-client
|
||||
tokens; the per-user ``sub`` check is the authorization gate.
|
||||
|
||||
Security note — bounded staleness: userinfo carries no token ``exp``, so
|
||||
a validated token is cached for ``userinfo_cache_ttl`` (5 min) rather
|
||||
than the 1-hour default. A revoked/expired opaque token may therefore be
|
||||
|
||||
@@ -665,6 +665,18 @@ class TestUserinfoFallback:
|
||||
result = await verifier._validate_via_userinfo("opaque-token")
|
||||
assert result is None
|
||||
|
||||
async def test_validate_via_userinfo_rejects_non_http_scheme(
|
||||
self, userinfo_settings
|
||||
):
|
||||
"""A non-http(s) userinfo_uri is refused before any request (SSRF guard)."""
|
||||
verifier = UnifiedTokenVerifier(userinfo_settings)
|
||||
verifier.userinfo_uri = "ftp://evil/userinfo"
|
||||
get_mock = AsyncMock()
|
||||
with patch.object(verifier.http_client, "get", get_mock):
|
||||
result = await verifier._validate_via_userinfo("opaque-token")
|
||||
assert result is None
|
||||
get_mock.assert_not_called()
|
||||
|
||||
async def test_validate_via_userinfo_not_configured(self, base_settings):
|
||||
base_settings.userinfo_uri = None
|
||||
verifier = UnifiedTokenVerifier(base_settings)
|
||||
|
||||
Reference in New Issue
Block a user