18
18
19
19
20
20
# The __init__.py will import this. Not the other way around.
21
- __version__ = "0.3.0 "
21
+ __version__ = "0.3.1 "
22
22
23
23
logger = logging .getLogger (__name__ )
24
24
@@ -104,17 +104,11 @@ def __init__(
104
104
# Here the self.authority is not the same type as authority in input
105
105
self .token_cache = token_cache or TokenCache ()
106
106
self .client = self ._build_client (client_credential , self .authority )
107
- self .authority_groups = self ._get_authority_aliases ()
108
-
109
- def _get_authority_aliases (self ):
110
- resp = requests .get (
111
- "https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https://login.microsoftonline.com/common/oauth2/authorize" ,
112
- headers = {'Accept' : 'application/json' })
113
- resp .raise_for_status ()
114
- return [set (group ['aliases' ]) for group in resp .json ()['metadata' ]]
107
+ self .authority_groups = None
115
108
116
109
def _build_client (self , client_credential , authority ):
117
110
client_assertion = None
111
+ client_assertion_type = None
118
112
default_body = {"client_info" : 1 }
119
113
if isinstance (client_credential , dict ):
120
114
assert ("private_key" in client_credential
@@ -124,6 +118,7 @@ def _build_client(self, client_credential, authority):
124
118
sha1_thumbprint = client_credential .get ("thumbprint" ))
125
119
client_assertion = signer .sign_assertion (
126
120
audience = authority .token_endpoint , issuer = self .client_id )
121
+ client_assertion_type = Client .CLIENT_ASSERTION_TYPE_JWT
127
122
else :
128
123
default_body ['client_secret' ] = client_credential
129
124
server_configuration = {
@@ -142,6 +137,7 @@ def _build_client(self, client_credential, authority):
142
137
},
143
138
default_body = default_body ,
144
139
client_assertion = client_assertion ,
140
+ client_assertion_type = client_assertion_type ,
145
141
on_obtaining_tokens = self .token_cache .add ,
146
142
on_removing_rt = self .token_cache .remove_rt ,
147
143
on_updating_rt = self .token_cache .update_rt ,
@@ -249,13 +245,10 @@ def get_accounts(self, username=None):
249
245
"""
250
246
accounts = self ._find_msal_accounts (environment = self .authority .instance )
251
247
if not accounts : # Now try other aliases of this authority instance
252
- for group in self .authority_groups :
253
- if self .authority .instance in group :
254
- for alias in group :
255
- if alias != self .authority .instance :
256
- accounts = self ._find_msal_accounts (environment = alias )
257
- if accounts :
258
- break
248
+ for alias in self ._get_authority_aliases (self .authority .instance ):
249
+ accounts = self ._find_msal_accounts (environment = alias )
250
+ if accounts :
251
+ break
259
252
if username :
260
253
# Federated account["username"] from AAD could contain mixed case
261
254
lowercase_username = username .lower ()
@@ -274,6 +267,19 @@ def _find_msal_accounts(self, environment):
274
267
if a ["authority_type" ] in (
275
268
TokenCache .AuthorityType .ADFS , TokenCache .AuthorityType .MSSTS )]
276
269
270
+ def _get_authority_aliases (self , instance ):
271
+ if not self .authority_groups :
272
+ resp = requests .get (
273
+ "https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https://login.microsoftonline.com/common/oauth2/authorize" ,
274
+ headers = {'Accept' : 'application/json' })
275
+ resp .raise_for_status ()
276
+ self .authority_groups = [
277
+ set (group ['aliases' ]) for group in resp .json ()['metadata' ]]
278
+ for group in self .authority_groups :
279
+ if instance in group :
280
+ return [alias for alias in group if alias != instance ]
281
+ return []
282
+
277
283
def acquire_token_silent (
278
284
self ,
279
285
scopes , # type: List[str]
@@ -309,19 +315,15 @@ def acquire_token_silent(
309
315
result = self ._acquire_token_silent (scopes , account , self .authority , ** kwargs )
310
316
if result :
311
317
return result
312
- for group in self .authority_groups :
313
- if self .authority .instance in group :
314
- for alias in group :
315
- if alias != self .authority .instance :
316
- the_authority = Authority (
317
- "https://" + alias + "/" + self .authority .tenant ,
318
- validate_authority = False ,
319
- verify = self .verify , proxies = self .proxies ,
320
- timeout = self .timeout ,)
321
- result = self ._acquire_token_silent (
322
- scopes , account , the_authority , ** kwargs )
323
- if result :
324
- return result
318
+ for alias in self ._get_authority_aliases (self .authority .instance ):
319
+ the_authority = Authority (
320
+ "https://" + alias + "/" + self .authority .tenant ,
321
+ validate_authority = False ,
322
+ verify = self .verify , proxies = self .proxies , timeout = self .timeout )
323
+ result = self ._acquire_token_silent (
324
+ scopes , account , the_authority , ** kwargs )
325
+ if result :
326
+ return result
325
327
326
328
def _acquire_token_silent (
327
329
self ,
@@ -466,6 +468,9 @@ def acquire_token_by_username_password(
466
468
self , username , password , scopes = None , ** kwargs ):
467
469
"""Gets a token for a given resource via user credentails.
468
470
471
+ See this page for constraints of Username Password Flow.
472
+ https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Username-Password-Authentication
473
+
469
474
:param str username: Typically a UPN in the form of an email address.
470
475
:param str password: The password.
471
476
:param list[str] scopes:
@@ -494,6 +499,11 @@ def _acquire_token_by_username_password_federated(
494
499
wstrust_endpoint = mex_send_request (
495
500
user_realm_result ["federation_metadata_url" ],
496
501
verify = verify , proxies = proxies )
502
+ if wstrust_endpoint is None :
503
+ raise ValueError ("Unable to find wstrust endpoint from MEX. "
504
+ "This typically happens when attempting MSA accounts. "
505
+ "More details available here. "
506
+ "https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Username-Password-Authentication" )
497
507
logger .debug ("wstrust_endpoint = %s" , wstrust_endpoint )
498
508
wstrust_result = wst_send_request (
499
509
username , password , user_realm_result .get ("cloud_audience_urn" ),
0 commit comments