Skip to content

Commit cb023ef

Browse files
authored
Merge pull request #62 from AzureAD/sovereign-support
Support sovereign cloud.
2 parents 4c52458 + 1e09105 commit cb023ef

File tree

2 files changed

+17
-26
lines changed

2 files changed

+17
-26
lines changed

msal/authority.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import re
2+
import logging
23

34
import requests
45

56
from .exceptions import MsalServiceError
67

78

9+
logger = logging.getLogger(__name__)
810
WORLD_WIDE = 'login.microsoftonline.com' # There was an alias login.windows.net
911
WELL_KNOWN_AUTHORITY_HOSTS = set([
1012
WORLD_WIDE,
@@ -38,14 +40,15 @@ def __init__(self, authority_url, validate_authority=True,
3840
canonicalized, self.instance, tenant = canonicalize(authority_url)
3941
tenant_discovery_endpoint = ( # Hard code a V2 pattern as default value
4042
'https://{}/{}/v2.0/.well-known/openid-configuration'
41-
.format(WORLD_WIDE, tenant))
43+
.format(self.instance, tenant))
4244
if validate_authority and self.instance not in WELL_KNOWN_AUTHORITY_HOSTS:
4345
tenant_discovery_endpoint = instance_discovery(
4446
canonicalized + "/oauth2/v2.0/authorize",
4547
verify=verify, proxies=proxies, timeout=timeout)
4648
openid_config = tenant_discovery(
4749
tenant_discovery_endpoint,
4850
verify=verify, proxies=proxies, timeout=timeout)
51+
logger.debug("openid_config = %s", openid_config)
4952
self.authorization_endpoint = openid_config['authorization_endpoint']
5053
self.token_endpoint = openid_config['token_endpoint']
5154
_, _, self.tenant = canonicalize(self.token_endpoint) # Usually a GUID
@@ -76,7 +79,11 @@ def canonicalize(url):
7679
def instance_discovery(url, response=None, **kwargs):
7780
# Returns tenant discovery endpoint
7881
resp = requests.get( # Note: This URL seemingly returns V1 endpoint only
79-
'https://{}/common/discovery/instance'.format(WORLD_WIDE),
82+
'https://{}/common/discovery/instance'.format(
83+
WORLD_WIDE # Historically using WORLD_WIDE. Could use self.instance too
84+
# See https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/blob/4.0.0/src/Microsoft.Identity.Client/Instance/AadInstanceDiscovery.cs#L101-L103
85+
# and https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/blob/4.0.0/src/Microsoft.Identity.Client/Instance/AadAuthority.cs#L19-L33
86+
),
8087
params={'authorization_endpoint': url, 'api-version': '1.0'},
8188
**kwargs)
8289
payload = response or resp.json()

tests/test_authority.py

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,16 @@
44

55

66
class TestAuthority(unittest.TestCase):
7-
COMMON_AUTH_ENDPOINT = \
8-
'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
9-
COMMON_TOKEN_ENDPOINT = \
10-
'https://login.microsoftonline.com/common/oauth2/v2.0/token'
117

128
def test_wellknown_host_and_tenant(self):
13-
# Test one specific sample in straightforward way, for readability
14-
a = Authority('https://login.microsoftonline.com/common')
15-
self.assertEqual(a.authorization_endpoint, self.COMMON_AUTH_ENDPOINT)
16-
self.assertEqual(a.token_endpoint, self.COMMON_TOKEN_ENDPOINT)
17-
18-
# Test all well known authority hosts, using same real "common" tenant
9+
# Assert all well known authority hosts are using their own "common" tenant
1910
for host in WELL_KNOWN_AUTHORITY_HOSTS:
2011
a = Authority('https://{}/common'.format(host))
21-
# Note: this "common" tenant endpoints always point to its real host
2212
self.assertEqual(
23-
a.authorization_endpoint, self.COMMON_AUTH_ENDPOINT)
24-
self.assertEqual(a.token_endpoint, self.COMMON_TOKEN_ENDPOINT)
13+
a.authorization_endpoint,
14+
'https://%s/common/oauth2/v2.0/authorize' % host)
15+
self.assertEqual(
16+
a.token_endpoint, 'https://%s/common/oauth2/v2.0/token' % host)
2517

2618
@unittest.skip("As of Jan 2017, the server no longer returns V1 endpoint")
2719
def test_lessknown_host_will_return_a_set_of_v1_endpoints(self):
@@ -33,20 +25,12 @@ def test_lessknown_host_will_return_a_set_of_v1_endpoints(self):
3325
self.assertEqual(a.token_endpoint, v1_token_endpoint)
3426
self.assertNotIn('v2.0', a.token_endpoint)
3527

36-
def test_unknown_host(self):
28+
def test_unknown_host_wont_pass_instance_discovery(self):
3729
with self.assertRaisesRegexp(MsalServiceError, "invalid_instance"):
3830
Authority('https://unknown.host/tenant_doesnt_matter_in_this_case')
3931

40-
def test_unknown_host_valid_tenant_and_skip_host_validation(self):
41-
# When skipping host (a.k.a. instance) validation,
42-
# the Tenant Discovery will always use WORLD_WIDE service as instance,
43-
# so, if the tenant happens to exist there, it will find some endpoints.
44-
a = Authority('https://incorrect.host/common', validate_authority=False)
45-
self.assertEqual(a.authorization_endpoint, self.COMMON_AUTH_ENDPOINT)
46-
self.assertEqual(a.token_endpoint, self.COMMON_TOKEN_ENDPOINT)
47-
48-
def test_unknown_host_unknown_tenant_and_skip_host_validation(self):
49-
with self.assertRaisesRegexp(MsalServiceError, "invalid_tenant"):
32+
def test_invalid_host_skipping_validation_meets_connection_error_down_the_road(self):
33+
with self.assertRaises(requests.exceptions.RequestException):
5034
Authority('https://unknown.host/invalid', validate_authority=False)
5135

5236

0 commit comments

Comments
 (0)