|
6 | 6 |
|
7 | 7 | import msal |
8 | 8 | from msal.authority import * |
9 | | -from msal.authority import _CIAM_DOMAIN_SUFFIX # Explicitly import the private constant |
| 9 | +from msal.authority import _CIAM_DOMAIN_SUFFIX, TRUSTED_ISSUER_HOSTS # Explicitly import private/new constants |
10 | 10 | from tests import unittest |
11 | 11 | from tests.http_client import MinimalHttpClient |
12 | 12 |
|
@@ -372,43 +372,122 @@ def test_invalid_issuer(self, tenant_discovery_mock): |
372 | 372 |
|
373 | 373 | @patch("msal.authority.tenant_discovery") |
374 | 374 | def test_custom_authority_with_microsoft_issuer(self, tenant_discovery_mock): |
375 | | - """Test when custom authority is used with a known Microsoft issuer (should fail)""" |
| 375 | + """Test when custom authority is used with a known Microsoft issuer (should succeed)""" |
376 | 376 | authority_url = "https://custom-domain.com/tenant" |
377 | 377 | issuer = f"https://{WORLD_WIDE}/tenant" |
| 378 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 379 | + self.assertTrue(authority.has_valid_issuer(), |
| 380 | + "Issuer from trusted Microsoft host should be valid even with custom authority") |
| 381 | + |
| 382 | + @patch("msal.authority.tenant_discovery") |
| 383 | + def test_known_authority_with_non_matching_issuer(self, tenant_discovery_mock): |
| 384 | + """Test when known authority is used with an issuer that doesn't match (should fail)""" |
| 385 | + # Known Microsoft authority URLs |
| 386 | + authority_url = f"https://{WORLD_WIDE}/tenant" |
| 387 | + issuer = "https://custom-domain.com/tenant" |
378 | 388 |
|
379 | 389 | tenant_discovery_mock.return_value = { |
380 | 390 | "authorization_endpoint": "https://example.com/oauth2/authorize", |
381 | 391 | "token_endpoint": "https://example.com/oauth2/token", |
382 | 392 | "issuer": issuer, |
383 | 393 | } |
384 | 394 |
|
385 | | - # Since initialization now checks for valid issuer and we removed the check for known hosts, |
386 | | - # we expect it to raise ValueError because the hosts don't match |
| 395 | + # We expect it to raise ValueError because the paths don't match |
| 396 | + # and we're now checking for exact matches |
387 | 397 | with self.assertRaises(ValueError) as context: |
388 | 398 | Authority(None, self.http_client, oidc_authority_url=authority_url) |
389 | 399 |
|
390 | 400 | self.assertIn("issuer", str(context.exception).lower()) |
391 | 401 | self.assertIn(issuer, str(context.exception)) |
392 | 402 | self.assertIn(authority_url, str(context.exception)) |
393 | 403 |
|
| 404 | + # Regional pattern tests |
394 | 405 | @patch("msal.authority.tenant_discovery") |
395 | | - def test_known_authority_with_non_matching_issuer(self, tenant_discovery_mock): |
396 | | - """Test when known authority is used with an issuer that doesn't match (should fail)""" |
397 | | - # Known Microsoft authority URLs |
398 | | - authority_url = f"https://{WORLD_WIDE}/tenant" |
399 | | - issuer = "https://custom-domain.com/tenant" |
| 406 | + def test_regional_issuer_westus2_login_microsoft(self, tenant_discovery_mock): |
| 407 | + """Test regional variant: westus2.login.microsoft.com""" |
| 408 | + authority_url = "https://custom-authority.com/tenant" |
| 409 | + issuer = "https://westus2.login.microsoftonline.com/tenant" |
| 410 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 411 | + self.assertTrue(authority.has_valid_issuer(), |
| 412 | + "Regional issuer westus2.login.microsoftonline.com should be valid") |
400 | 413 |
|
| 414 | + @patch("msal.authority.tenant_discovery") |
| 415 | + def test_regional_issuer_eastus_login_microsoftonline(self, tenant_discovery_mock): |
| 416 | + """Test regional variant: eastus.login.microsoftonline.com""" |
| 417 | + authority_url = "https://custom-authority.com/tenant" |
| 418 | + issuer = "https://eastus.login.microsoftonline.com/tenant" |
| 419 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 420 | + self.assertTrue(authority.has_valid_issuer(), |
| 421 | + "Regional issuer eastus.login.microsoftonline.com should be valid") |
| 422 | + |
| 423 | + @patch("msal.authority.tenant_discovery") |
| 424 | + def test_regional_issuer_for_china_cloud(self, tenant_discovery_mock): |
| 425 | + """Test regional variant for China cloud: region.login.chinacloudapi.cn""" |
| 426 | + authority_url = "https://custom-authority.com/tenant" |
| 427 | + issuer = "https://chinanorth.login.chinacloudapi.cn/tenant" |
| 428 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 429 | + self.assertTrue(authority.has_valid_issuer(), |
| 430 | + "Regional issuer for China cloud should be valid") |
| 431 | + |
| 432 | + @patch("msal.authority.tenant_discovery") |
| 433 | + def test_regional_issuer_for_us_government(self, tenant_discovery_mock): |
| 434 | + """Test regional variant for US Government: region.login.microsoftonline.us""" |
| 435 | + authority_url = "https://custom-authority.com/tenant" |
| 436 | + issuer = "https://usgovvirginia.login.microsoftonline.us/tenant" |
| 437 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 438 | + self.assertTrue(authority.has_valid_issuer(), |
| 439 | + "Regional issuer for US Government should be valid") |
| 440 | + |
| 441 | + @patch("msal.authority.tenant_discovery") |
| 442 | + def test_invalid_regional_pattern_with_dots_in_region(self, tenant_discovery_mock): |
| 443 | + """Test that region with dots is rejected: west.us.2.login.microsoftonline.com""" |
| 444 | + authority_url = "https://custom-authority.com/tenant" |
| 445 | + issuer = "https://west.us.2.login.microsoftonline.com/tenant" |
401 | 446 | tenant_discovery_mock.return_value = { |
402 | 447 | "authorization_endpoint": "https://example.com/oauth2/authorize", |
403 | 448 | "token_endpoint": "https://example.com/oauth2/token", |
404 | 449 | "issuer": issuer, |
405 | 450 | } |
| 451 | + with self.assertRaises(ValueError): |
| 452 | + Authority(None, self.http_client, oidc_authority_url=authority_url) |
406 | 453 |
|
407 | | - # We expect it to raise ValueError because the paths don't match |
408 | | - # and we're now checking for exact matches |
409 | | - with self.assertRaises(ValueError) as context: |
| 454 | + @patch("msal.authority.tenant_discovery") |
| 455 | + def test_invalid_regional_pattern_untrusted_base(self, tenant_discovery_mock): |
| 456 | + """Test that regional pattern with untrusted base is rejected""" |
| 457 | + authority_url = "https://custom-authority.com/tenant" |
| 458 | + issuer = "https://westus2.login.evil.com/tenant" # evil.com is not trusted |
| 459 | + tenant_discovery_mock.return_value = { |
| 460 | + "authorization_endpoint": "https://example.com/oauth2/authorize", |
| 461 | + "token_endpoint": "https://example.com/oauth2/token", |
| 462 | + "issuer": issuer, |
| 463 | + } |
| 464 | + with self.assertRaises(ValueError): |
410 | 465 | Authority(None, self.http_client, oidc_authority_url=authority_url) |
411 | 466 |
|
412 | | - self.assertIn("issuer", str(context.exception).lower()) |
413 | | - self.assertIn(issuer, str(context.exception)) |
414 | | - self.assertIn(authority_url, str(context.exception)) |
| 467 | + @patch("msal.authority.tenant_discovery") |
| 468 | + def test_well_known_host_issuer_directly(self, tenant_discovery_mock): |
| 469 | + """Test issuer from well-known Microsoft host directly (not regional)""" |
| 470 | + authority_url = "https://custom-authority.com/tenant" |
| 471 | + issuer = f"https://{WORLD_WIDE}/tenant" |
| 472 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 473 | + self.assertTrue(authority.has_valid_issuer(), |
| 474 | + "Issuer from well-known Microsoft host should be valid") |
| 475 | + |
| 476 | + @patch("msal.authority.tenant_discovery") |
| 477 | + def test_issuer_with_trailing_slash_match(self, tenant_discovery_mock): |
| 478 | + """Test issuer validation handles trailing slashes""" |
| 479 | + authority_url = "https://example.com/tenant/" |
| 480 | + issuer = "https://example.com/tenant" # No trailing slash |
| 481 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 482 | + self.assertTrue(authority.has_valid_issuer(), |
| 483 | + "Trailing slash difference should not affect exact match") |
| 484 | + |
| 485 | + @patch("msal.authority.tenant_discovery") |
| 486 | + def test_issuer_case_sensitivity_host(self, tenant_discovery_mock): |
| 487 | + """Test that host comparison is case-insensitive for regional check""" |
| 488 | + authority_url = "https://custom-authority.com/tenant" |
| 489 | + issuer = "https://WESTUS2.LOGIN.MICROSOFTONLINE.COM/tenant" # Uppercase |
| 490 | + authority = self._create_authority_with_issuer(authority_url, issuer, tenant_discovery_mock) |
| 491 | + self.assertTrue(authority.has_valid_issuer(), |
| 492 | + "Host comparison should be case-insensitive") |
| 493 | + |
0 commit comments