fix(auth): normalize explicit default ports in resource_url_from_server_url (RFC 3986) - #3310
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 2 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- _canonical_netloc now catches ValueError from parsed.port for malformed explicit ports (e.g. out-of-range), falling back to the original netloc instead of letting check_resource_allowed() crash - add test coverage for the userinfo-in-netloc and IPv6-literal branches that were previously untested (CI requires 100% coverage) - add regression test for the malformed-port fallback
|
Thanks for the contribution. This repository only keeps pull requests open when they're linked to an issue that a maintainer has assigned to the author — CONTRIBUTING.md explains why and how we work. This PR has been closed for now because you aren't currently assigned to #3297. If a maintainer would like this change as a PR from you, they'll assign you to #3297 and this PR will reopen automatically — there's nothing more you need to do. (If you opened the issue, this PR already shows up on its timeline.) There's no need to open a new PR — this one will be reopened. While it's closed, please push any updates as new commits rather than force-pushing, since GitHub can't reopen a PR whose branch has been rewritten. Maintainers: reopening this PR, removing the |
Summary
Fixes #3297.
resource_url_from_server_url()lowercases the scheme/authority and strips URL fragments, but previously preserved explicitly specified default ports (:80for HTTP,:443for HTTPS).Per RFC 3986 §6.2.3 (Scheme-Based Normalization), an explicit default port is equivalent to an omitted port. Furthermore, Pydantic's
HttpUrlautomatically normalizes metadata URLs by dropping default ports. Becauseresource_url_from_server_url()preserved them,check_resource_allowed()would reject an otherwise identical resource (e.g. comparinghttps://example.com:443/mcpagainsthttps://example.com/mcp), leading to false-positive authorization failures.Changes
_canonical_netloc()Helper: Normalizes netloc by stripping default port80forhttpand443forhttps, while preserving non-default ports, userinfo, and IPv6 literals.check_resource_allowed(): Canonicalizes bothrequested_resourceandconfigured_resourcebefore parsing to guarantee consistent comparison across equivalent URL representations.80and443are stripped from canonical resource URLs while non-default ports like8443or8080are preserved.check_resource_allowed()correctly evaluates matching resources regardless of explicit default port notation in either parameter.Verification
uv run pytest tests/shared/test_auth_utils.py tests/client/test_auth.py: 155 passed, 1 xfailed (pre-existing).