-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Expand file tree
/
Copy pathtest_routes.py
More file actions
113 lines (71 loc) · 4.41 KB
/
Copy pathtest_routes.py
File metadata and controls
113 lines (71 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import pytest
from pydantic import AnyHttpUrl, AnyUrl
from mcp.server.auth.routes import build_metadata, validate_issuer_url
from mcp.server.auth.settings import AuthSettings, ClientRegistrationOptions, RevocationOptions
from mcp.server.auth.url_validators import validate_redirect_uri
def test_validate_issuer_url_https_allowed():
validate_issuer_url(AnyHttpUrl("https://example.com/path"))
def test_validate_issuer_url_http_localhost_allowed():
validate_issuer_url(AnyHttpUrl("http://localhost:8080/path"))
def test_validate_issuer_url_http_127_0_0_1_allowed():
validate_issuer_url(AnyHttpUrl("http://127.0.0.1:8080/path"))
def test_validate_issuer_url_http_ipv6_loopback_allowed():
validate_issuer_url(AnyHttpUrl("http://[::1]:8080/path"))
def test_validate_issuer_url_http_non_loopback_rejected():
with pytest.raises(ValueError, match="Issuer URL must be HTTPS"):
validate_issuer_url(AnyHttpUrl("http://evil.com/path"))
def test_validate_issuer_url_http_127_prefix_domain_rejected():
"""A domain like 127.0.0.1.evil.com is not loopback."""
with pytest.raises(ValueError, match="Issuer URL must be HTTPS"):
validate_issuer_url(AnyHttpUrl("http://127.0.0.1.evil.com/path"))
def test_validate_issuer_url_http_127_prefix_subdomain_rejected():
"""A domain like 127.0.0.1something.example.com is not loopback."""
with pytest.raises(ValueError, match="Issuer URL must be HTTPS"):
validate_issuer_url(AnyHttpUrl("http://127.0.0.1something.example.com/path"))
def test_validate_issuer_url_fragment_rejected():
with pytest.raises(ValueError, match="fragment"):
validate_issuer_url(AnyHttpUrl("https://example.com/path#frag"))
def test_validate_issuer_url_query_rejected():
with pytest.raises(ValueError, match="query"):
validate_issuer_url(AnyHttpUrl("https://example.com/path?q=1"))
def test_auth_settings_preserves_path_less_issuer():
"""A path-less issuer passed as a string keeps its canonical form (no trailing slash)."""
settings = AuthSettings(
issuer_url="https://as.example.com", # type: ignore[arg-type]
resource_server_url="https://rs.example.com", # type: ignore[arg-type]
)
assert str(settings.issuer_url) == "https://as.example.com"
assert str(settings.resource_server_url) == "https://rs.example.com"
def test_build_metadata_serves_issuer_without_trailing_slash():
"""The served issuer matches the configured one exactly (RFC 8414/9207 string comparison)."""
settings = AuthSettings(
issuer_url="https://as.example.com", # type: ignore[arg-type]
resource_server_url="https://rs.example.com", # type: ignore[arg-type]
)
metadata = build_metadata(settings.issuer_url, None, ClientRegistrationOptions(), RevocationOptions())
served = metadata.model_dump(mode="json", exclude_none=True)
assert served["issuer"] == "https://as.example.com"
assert served["authorization_endpoint"] == "https://as.example.com/authorize"
assert served["token_endpoint"] == "https://as.example.com/token"
def test_validate_redirect_uri_https_allowed():
validate_redirect_uri(AnyHttpUrl("https://example.com/cb"))
def test_validate_redirect_uri_http_localhost_allowed():
validate_redirect_uri(AnyHttpUrl("http://localhost:3000/cb"))
def test_validate_redirect_uri_http_127_0_0_1_allowed():
validate_redirect_uri(AnyHttpUrl("http://127.0.0.1:8080/cb"))
def test_validate_redirect_uri_http_ipv6_loopback_allowed():
validate_redirect_uri(AnyHttpUrl("http://[::1]:9090/cb"))
def test_validate_redirect_uri_javascript_scheme_rejected():
with pytest.raises(ValueError, match="Redirect URI must use an HTTP"):
validate_redirect_uri(AnyUrl("javascript:alert(1)"))
def test_validate_redirect_uri_file_scheme_rejected():
with pytest.raises(ValueError, match="Redirect URI must use an HTTP"):
validate_redirect_uri(AnyUrl("file:///etc/passwd"))
def test_validate_redirect_uri_http_non_loopback_allowed():
validate_redirect_uri(AnyHttpUrl("http://evil.com/cb"))
def test_validate_redirect_uri_fragment_rejected():
with pytest.raises(ValueError, match="Redirect URI must not contain a fragment"):
validate_redirect_uri(AnyHttpUrl("https://example.com/cb#frag"))
def test_validate_redirect_uri_empty_fragment_rejected():
with pytest.raises(ValueError, match="Redirect URI must not contain a fragment"):
validate_redirect_uri(AnyHttpUrl("https://example.com/cb#"))