Skip to content

Commit 5ef747f

Browse files
committed
Add cloud instances string constants
Reduce duplicated magic strings Add test cases Writing docs
1 parent 23e5341 commit 5ef747f

File tree

4 files changed

+72
-11
lines changed

4 files changed

+72
-11
lines changed

msal/application.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,23 @@ def __init__(
231231
232232
:param str authority:
233233
A URL that identifies a token authority. It should be of the format
234-
https://login.microsoftonline.com/your_tenant
235-
By default, we will use https://login.microsoftonline.com/common
234+
``https://login.microsoftonline.com/your_tenant``
235+
By default, we will use ``https://login.microsoftonline.com/common``
236+
237+
*Changed in version 1.17*: you can also use predefined constant
238+
and a builder like this::
239+
240+
from msal.authority import (
241+
AuthorityBuilder,
242+
AZURE_US_GOVERNMENT, AZURE_CHINA, AZURE_PUBLIC)
243+
my_authority = AuthorityBuilder(AZURE_PUBLIC, "contoso.onmicrosoft.com")
244+
# Now you get an equivalent of
245+
# "https://login.microsoftonline.com/contoso.onmicrosoft.com"
246+
247+
# You can feed such an authority to msal's ClientApplication
248+
from msal import PublicClientApplication
249+
app = PublicClientApplication("my_client_id", authority=my_authority, ...)
250+
236251
:param bool validate_authority: (optional) Turns authority validation
237252
on or off. This parameter default to true.
238253
:param TokenCache cache:

msal/authority.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,19 @@
1414

1515

1616
logger = logging.getLogger(__name__)
17+
18+
# Endpoints were copied from here
19+
# https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-national-cloud#azure-ad-authentication-endpoints
20+
AZURE_US_GOVERNMENT = "login.microsoftonline.us"
21+
AZURE_CHINA = "login.chinacloudapi.cn"
22+
AZURE_PUBLIC = "login.microsoftonline.com"
23+
1724
WORLD_WIDE = 'login.microsoftonline.com' # There was an alias login.windows.net
1825
WELL_KNOWN_AUTHORITY_HOSTS = set([
1926
WORLD_WIDE,
20-
'login.chinacloudapi.cn',
27+
AZURE_CHINA,
2128
'login-us.microsoftonline.com',
22-
'login.microsoftonline.us',
29+
AZURE_US_GOVERNMENT,
2330
'login.microsoftonline.de',
2431
])
2532
WELL_KNOWN_B2C_HOSTS = [
@@ -30,6 +37,19 @@
3037
]
3138

3239

40+
class AuthorityBuilder(object):
41+
def __init__(self, instance, tenant):
42+
"""A helper to save caller from doing string concatenation.
43+
44+
Usage is documented in :func:`application.ClientApplication.__init__`.
45+
"""
46+
self._instance = instance.rstrip("/")
47+
self._tenant = tenant.strip("/")
48+
49+
def __str__(self):
50+
return "https://{}/{}".format(self._instance, self._tenant)
51+
52+
3353
class Authority(object):
3454
"""This class represents an (already-validated) authority.
3555
@@ -53,6 +73,8 @@ def __init__(self, authority_url, http_client, validate_authority=True):
5373
performed.
5474
"""
5575
self._http_client = http_client
76+
if isinstance(authority_url, AuthorityBuilder):
77+
authority_url = str(authority_url)
5678
authority, self.instance, tenant = canonicalize(authority_url)
5779
parts = authority.path.split('/')
5880
is_b2c = any(self.instance.endswith("." + d) for d in WELL_KNOWN_B2C_HOSTS) or (

tests/http_client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ def get(self, url, params=None, headers=None, **kwargs):
2020
return MinimalResponse(requests_resp=self.session.get(
2121
url, params=params, headers=headers, timeout=self.timeout))
2222

23+
def close(self): # Not required, but we use it to avoid a warning in unit test
24+
self.session.close()
25+
2326

2427
class MinimalResponse(object): # Not for production use
2528
def __init__(self, requests_resp=None, status_code=None, text=None):

tests/test_authority.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,37 @@
88
@unittest.skipIf(os.getenv("TRAVIS_TAG"), "Skip network io during tagged release")
99
class TestAuthority(unittest.TestCase):
1010

11+
def _test_given_host_and_tenant(self, host, tenant):
12+
c = MinimalHttpClient()
13+
a = Authority('https://{}/{}'.format(host, tenant), c)
14+
self.assertEqual(
15+
a.authorization_endpoint,
16+
'https://{}/{}/oauth2/v2.0/authorize'.format(host, tenant))
17+
self.assertEqual(
18+
a.token_endpoint,
19+
'https://{}/{}/oauth2/v2.0/token'.format(host, tenant))
20+
c.close()
21+
22+
def _test_authority_builder(self, host, tenant):
23+
c = MinimalHttpClient()
24+
a = Authority(AuthorityBuilder(host, tenant), c)
25+
self.assertEqual(
26+
a.authorization_endpoint,
27+
'https://{}/{}/oauth2/v2.0/authorize'.format(host, tenant))
28+
self.assertEqual(
29+
a.token_endpoint,
30+
'https://{}/{}/oauth2/v2.0/token'.format(host, tenant))
31+
c.close()
32+
1133
def test_wellknown_host_and_tenant(self):
1234
# Assert all well known authority hosts are using their own "common" tenant
1335
for host in WELL_KNOWN_AUTHORITY_HOSTS:
14-
a = Authority(
15-
'https://{}/common'.format(host), MinimalHttpClient())
16-
self.assertEqual(
17-
a.authorization_endpoint,
18-
'https://%s/common/oauth2/v2.0/authorize' % host)
19-
self.assertEqual(
20-
a.token_endpoint, 'https://%s/common/oauth2/v2.0/token' % host)
36+
self._test_given_host_and_tenant(host, "common")
37+
38+
def test_wellknown_host_and_tenant_using_new_authority_builder(self):
39+
self._test_authority_builder(AZURE_PUBLIC, "consumers")
40+
self._test_authority_builder(AZURE_CHINA, "organizations")
41+
self._test_authority_builder(AZURE_US_GOVERNMENT, "common")
2142

2243
@unittest.skip("As of Jan 2017, the server no longer returns V1 endpoint")
2344
def test_lessknown_host_will_return_a_set_of_v1_endpoints(self):

0 commit comments

Comments
 (0)