diff --git a/packages/abstractions/kiota_abstractions/authentication/allowed_hosts_validator.py b/packages/abstractions/kiota_abstractions/authentication/allowed_hosts_validator.py index 577faebf..201055ea 100644 --- a/packages/abstractions/kiota_abstractions/authentication/allowed_hosts_validator.py +++ b/packages/abstractions/kiota_abstractions/authentication/allowed_hosts_validator.py @@ -67,4 +67,12 @@ def is_url_host_valid(self, url: str) -> bool: return False if not o.hostname: return False - return o.hostname.lower() in self.allowed_hosts + hostname = o.hostname.lower() + # Existing exact match + if hostname in self.allowed_hosts: + return True + # Suffix match for entries starting with "." + return any( + suffix.startswith(".") and hostname.endswith(suffix) + for suffix in self.allowed_hosts + ) diff --git a/packages/abstractions/tests/authentication/test_allowed_hosts_validator.py b/packages/abstractions/tests/authentication/test_allowed_hosts_validator.py index 1f4d6d41..d07942a7 100644 --- a/packages/abstractions/tests/authentication/test_allowed_hosts_validator.py +++ b/packages/abstractions/tests/authentication/test_allowed_hosts_validator.py @@ -62,11 +62,28 @@ def test_validates_subdomain_separately(self): validator = AllowedHostsValidator(["example.com"]) assert validator.is_url_host_valid("https://sub.example.com/path") is False + def test_returns_true_for_subdomain_matching_allowed_suffix(self): + validator = AllowedHostsValidator([".fabric.microsoft.com"]) + assert validator.is_url_host_valid( + "https://abc.123.graphql.fabric.microsoft.com/path" + ) is True + + def test_returns_false_for_bare_domain_when_allowed_as_suffix(self): + validator = AllowedHostsValidator([".fabric.microsoft.com"]) + assert validator.is_url_host_valid("https://fabric.microsoft.com/path") is False + + def test_suffix_host_matching_is_case_insensitive(self): + validator = AllowedHostsValidator([".Fabric.Microsoft.COM"]) + assert validator.is_url_host_valid("https://ABC.z2c.graphql.fabric.microsoft.com/path") is True + def test_allows_multiple_valid_hosts(self): - validator = AllowedHostsValidator(["example.com", "api.example.com"]) + validator = AllowedHostsValidator(["example.com", "api.example.com", ".fabric.microsoft.com"]) assert validator.is_url_host_valid("https://example.com/path") is True assert validator.is_url_host_valid("https://api.example.com/path") is True assert validator.is_url_host_valid("https://other.com/path") is False + assert validator.is_url_host_valid( + "https://abc.123.graphql.fabric.microsoft.com/path" + ) is True def test_handles_url_with_port(self): validator = AllowedHostsValidator(["example.com"]) @@ -93,3 +110,10 @@ def test_raises_on_http_prefix(self): validator = AllowedHostsValidator(["example.com"]) with pytest.raises(ValueError): validator.set_allowed_hosts(["http://example.com"]) + + def test_allows_suffix_based_hosts_after_update(self): + validator = AllowedHostsValidator(["example.com"]) + validator.set_allowed_hosts([".fabric.microsoft.com"]) + assert validator.is_url_host_valid( + "https://abc.123.graphql.fabric.microsoft.com/path" + ) is True