11"""Tests for OAuth 2.0 Resource Indicators utilities."""
22
3- import pytest
4-
53from mcp .shared .auth_utils import check_resource_allowed , resource_url_from_server_url
64
75
86class TestResourceUrlFromServerUrl :
97 """Tests for resource_url_from_server_url function."""
10-
8+
119 def test_removes_fragment (self ):
1210 """Fragment should be removed per RFC 8707."""
1311 assert resource_url_from_server_url ("https://example.com/path#fragment" ) == "https://example.com/path"
1412 assert resource_url_from_server_url ("https://example.com/#fragment" ) == "https://example.com/"
15-
13+
1614 def test_preserves_path (self ):
1715 """Path should be preserved."""
18- assert resource_url_from_server_url ("https://example.com/path/to/resource" ) == "https://example.com/path/to/resource"
16+ assert (
17+ resource_url_from_server_url ("https://example.com/path/to/resource" )
18+ == "https://example.com/path/to/resource"
19+ )
1920 assert resource_url_from_server_url ("https://example.com/" ) == "https://example.com/"
2021 assert resource_url_from_server_url ("https://example.com" ) == "https://example.com"
21-
22+
2223 def test_preserves_query (self ):
2324 """Query parameters should be preserved."""
2425 assert resource_url_from_server_url ("https://example.com/path?foo=bar" ) == "https://example.com/path?foo=bar"
2526 assert resource_url_from_server_url ("https://example.com/?key=value" ) == "https://example.com/?key=value"
26-
27+
2728 def test_preserves_port (self ):
2829 """Non-default ports should be preserved."""
2930 assert resource_url_from_server_url ("https://example.com:8443/path" ) == "https://example.com:8443/path"
3031 assert resource_url_from_server_url ("http://example.com:8080/" ) == "http://example.com:8080/"
31-
32+
3233 def test_lowercase_scheme_and_host (self ):
3334 """Scheme and host should be lowercase for canonical form."""
3435 assert resource_url_from_server_url ("HTTPS://EXAMPLE.COM/path" ) == "https://example.com/path"
3536 assert resource_url_from_server_url ("Http://Example.Com:8080/" ) == "http://example.com:8080/"
36-
37+
3738 def test_handles_pydantic_urls (self ):
3839 """Should handle Pydantic URL types."""
3940 from pydantic import HttpUrl
40-
41+
4142 url = HttpUrl ("https://example.com/path" )
4243 assert resource_url_from_server_url (url ) == "https://example.com/path"
4344
4445
4546class TestCheckResourceAllowed :
4647 """Tests for check_resource_allowed function."""
47-
48+
4849 def test_identical_urls (self ):
4950 """Identical URLs should match."""
5051 assert check_resource_allowed ("https://example.com/path" , "https://example.com/path" ) is True
5152 assert check_resource_allowed ("https://example.com/" , "https://example.com/" ) is True
5253 assert check_resource_allowed ("https://example.com" , "https://example.com" ) is True
53-
54+
5455 def test_different_schemes (self ):
5556 """Different schemes should not match."""
5657 assert check_resource_allowed ("https://example.com/path" , "http://example.com/path" ) is False
5758 assert check_resource_allowed ("http://example.com/" , "https://example.com/" ) is False
58-
59+
5960 def test_different_domains (self ):
6061 """Different domains should not match."""
6162 assert check_resource_allowed ("https://example.com/path" , "https://example.org/path" ) is False
6263 assert check_resource_allowed ("https://sub.example.com/" , "https://example.com/" ) is False
63-
64+
6465 def test_different_ports (self ):
6566 """Different ports should not match."""
6667 assert check_resource_allowed ("https://example.com:8443/path" , "https://example.com/path" ) is False
6768 assert check_resource_allowed ("https://example.com:8080/" , "https://example.com:8443/" ) is False
68-
69+
6970 def test_hierarchical_matching (self ):
7071 """Child paths should match parent paths."""
7172 # Parent resource allows child resources
7273 assert check_resource_allowed ("https://example.com/api/v1/users" , "https://example.com/api" ) is True
7374 assert check_resource_allowed ("https://example.com/api/v1" , "https://example.com/api" ) is True
7475 assert check_resource_allowed ("https://example.com/mcp/server" , "https://example.com/mcp" ) is True
75-
76+
7677 # Exact match
7778 assert check_resource_allowed ("https://example.com/api" , "https://example.com/api" ) is True
78-
79+
7980 # Parent cannot use child's token
8081 assert check_resource_allowed ("https://example.com/api" , "https://example.com/api/v1" ) is False
8182 assert check_resource_allowed ("https://example.com/" , "https://example.com/api" ) is False
82-
83+
8384 def test_path_boundary_matching (self ):
8485 """Path matching should respect boundaries."""
8586 # Should not match partial path segments
8687 assert check_resource_allowed ("https://example.com/apiextra" , "https://example.com/api" ) is False
8788 assert check_resource_allowed ("https://example.com/api123" , "https://example.com/api" ) is False
88-
89+
8990 # Should match with trailing slash
9091 assert check_resource_allowed ("https://example.com/api/" , "https://example.com/api" ) is True
9192 assert check_resource_allowed ("https://example.com/api/v1" , "https://example.com/api/" ) is True
92-
93+
9394 def test_trailing_slash_handling (self ):
9495 """Trailing slashes should be handled correctly."""
9596 # With and without trailing slashes
9697 assert check_resource_allowed ("https://example.com/api/" , "https://example.com/api" ) is True
9798 assert check_resource_allowed ("https://example.com/api" , "https://example.com/api/" ) is False
9899 assert check_resource_allowed ("https://example.com/api/v1" , "https://example.com/api" ) is True
99100 assert check_resource_allowed ("https://example.com/api/v1" , "https://example.com/api/" ) is True
100-
101+
101102 def test_case_insensitive_origin (self ):
102103 """Origin comparison should be case-insensitive."""
103104 assert check_resource_allowed ("https://EXAMPLE.COM/path" , "https://example.com/path" ) is True
104105 assert check_resource_allowed ("HTTPS://example.com/path" , "https://example.com/path" ) is True
105106 assert check_resource_allowed ("https://Example.Com:8080/api" , "https://example.com:8080/api" ) is True
106-
107+
107108 def test_empty_paths (self ):
108109 """Empty paths should be handled correctly."""
109110 assert check_resource_allowed ("https://example.com" , "https://example.com" ) is True
110111 assert check_resource_allowed ("https://example.com/" , "https://example.com" ) is True
111- assert check_resource_allowed ("https://example.com/api" , "https://example.com" ) is True
112+ assert check_resource_allowed ("https://example.com/api" , "https://example.com" ) is True
0 commit comments