1
+ import functools
2
+ import json
1
3
import time
2
4
try : # Python 2
3
5
from urlparse import urljoin
@@ -54,11 +56,11 @@ def decorate_scope(
54
56
CLIENT_CURRENT_TELEMETRY = 'x-client-current-telemetry'
55
57
56
58
def _get_new_correlation_id ():
57
- return str (uuid .uuid4 ())
59
+ return str (uuid .uuid4 ())
58
60
59
61
60
62
def _build_current_telemetry_request_header (public_api_id , force_refresh = False ):
61
- return "1|{},{}|" .format (public_api_id , "1" if force_refresh else "0" )
63
+ return "1|{},{}|" .format (public_api_id , "1" if force_refresh else "0" )
62
64
63
65
64
66
def extract_certs (public_cert_content ):
@@ -92,6 +94,7 @@ def __init__(
92
94
self , client_id ,
93
95
client_credential = None , authority = None , validate_authority = True ,
94
96
token_cache = None ,
97
+ http_client = None ,
95
98
verify = True , proxies = None , timeout = None ,
96
99
client_claims = None , app_name = None , app_version = None ):
97
100
"""Create an instance of application.
@@ -151,18 +154,24 @@ def __init__(
151
154
:param TokenCache cache:
152
155
Sets the token cache used by this ClientApplication instance.
153
156
By default, an in-memory cache will be created and used.
157
+ :param http_client: (optional)
158
+ Your implementation of abstract class HttpClient <msal.oauth2cli.http.http_client>
159
+ Defaults to a requests session instance
154
160
:param verify: (optional)
155
161
It will be passed to the
156
162
`verify parameter in the underlying requests library
157
163
<http://docs.python-requests.org/en/v2.9.1/user/advanced/#ssl-cert-verification>`_
164
+ This does not apply if you have chosen to pass your own Http client
158
165
:param proxies: (optional)
159
166
It will be passed to the
160
167
`proxies parameter in the underlying requests library
161
168
<http://docs.python-requests.org/en/v2.9.1/user/advanced/#proxies>`_
169
+ This does not apply if you have chosen to pass your own Http client
162
170
:param timeout: (optional)
163
171
It will be passed to the
164
172
`timeout parameter in the underlying requests library
165
173
<http://docs.python-requests.org/en/v2.9.1/user/advanced/#timeouts>`_
174
+ This does not apply if you have chosen to pass your own Http client
166
175
:param app_name: (optional)
167
176
You can provide your application name for Microsoft telemetry purposes.
168
177
Default value is None, means it will not be passed to Microsoft.
@@ -173,14 +182,21 @@ def __init__(
173
182
self .client_id = client_id
174
183
self .client_credential = client_credential
175
184
self .client_claims = client_claims
176
- self .verify = verify
177
- self .proxies = proxies
178
- self .timeout = timeout
185
+ if http_client :
186
+ self .http_client = http_client
187
+ else :
188
+ self .http_client = requests .Session ()
189
+ self .http_client .verify = verify
190
+ self .http_client .proxies = proxies
191
+ # Requests, does not support session - wide timeout
192
+ # But you can patch that (https://github.com/psf/requests/issues/3341):
193
+ self .http_client .request = functools .partial (
194
+ self .http_client .request , timeout = timeout )
179
195
self .app_name = app_name
180
196
self .app_version = app_version
181
197
self .authority = Authority (
182
198
authority or "https://login.microsoftonline.com/common/" ,
183
- validate_authority , verify = verify , proxies = proxies , timeout = timeout )
199
+ self . http_client , validate_authority = validate_authority )
184
200
# Here the self.authority is not the same type as authority in input
185
201
self .token_cache = token_cache or TokenCache ()
186
202
self .client = self ._build_client (client_credential , self .authority )
@@ -223,14 +239,14 @@ def _build_client(self, client_credential, authority):
223
239
return Client (
224
240
server_configuration ,
225
241
self .client_id ,
242
+ http_client = self .http_client ,
226
243
default_headers = default_headers ,
227
244
default_body = default_body ,
228
245
client_assertion = client_assertion ,
229
246
client_assertion_type = client_assertion_type ,
230
247
on_obtaining_tokens = self .token_cache .add ,
231
248
on_removing_rt = self .token_cache .remove_rt ,
232
- on_updating_rt = self .token_cache .update_rt ,
233
- verify = self .verify , proxies = self .proxies , timeout = self .timeout )
249
+ on_updating_rt = self .token_cache .update_rt )
234
250
235
251
def get_authorization_request_url (
236
252
self ,
@@ -288,12 +304,13 @@ def get_authorization_request_url(
288
304
# Multi-tenant app can use new authority on demand
289
305
the_authority = Authority (
290
306
authority ,
291
- verify = self .verify , proxies = self . proxies , timeout = self . timeout ,
307
+ self .http_client
292
308
) if authority else self .authority
293
309
294
310
client = Client (
295
311
{"authorization_endpoint" : the_authority .authorization_endpoint },
296
- self .client_id )
312
+ self .client_id ,
313
+ http_client = self .http_client )
297
314
return client .build_auth_request_uri (
298
315
response_type = response_type ,
299
316
redirect_uri = redirect_uri , state = state , login_hint = login_hint ,
@@ -399,13 +416,12 @@ def _find_msal_accounts(self, environment):
399
416
400
417
def _get_authority_aliases (self , instance ):
401
418
if not self .authority_groups :
402
- resp = requests .get (
419
+ resp = self . http_client .get (
403
420
"https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https://login.microsoftonline.com/common/oauth2/authorize" ,
404
- headers = {'Accept' : 'application/json' },
405
- verify = self .verify , proxies = self .proxies , timeout = self .timeout )
421
+ headers = {'Accept' : 'application/json' })
406
422
resp .raise_for_status ()
407
423
self .authority_groups = [
408
- set (group ['aliases' ]) for group in resp . json ( )['metadata' ]]
424
+ set (group ['aliases' ]) for group in json . loads ( resp . text )['metadata' ]]
409
425
for group in self .authority_groups :
410
426
if instance in group :
411
427
return [alias for alias in group if alias != instance ]
@@ -524,7 +540,7 @@ def acquire_token_silent_with_error(
524
540
warnings .warn ("We haven't decided how/if this method will accept authority parameter" )
525
541
# the_authority = Authority(
526
542
# authority,
527
- # verify= self.verify, proxies=self.proxies, timeout=self.timeout ,
543
+ # self.http_client ,
528
544
# ) if authority else self.authority
529
545
result = self ._acquire_token_silent_from_cache_and_possibly_refresh_it (
530
546
scopes , account , self .authority , force_refresh = force_refresh ,
@@ -536,8 +552,8 @@ def acquire_token_silent_with_error(
536
552
for alias in self ._get_authority_aliases (self .authority .instance ):
537
553
the_authority = Authority (
538
554
"https://" + alias + "/" + self .authority .tenant ,
539
- validate_authority = False ,
540
- verify = self . verify , proxies = self . proxies , timeout = self . timeout )
555
+ self . http_client ,
556
+ validate_authority = False )
541
557
result = self ._acquire_token_silent_from_cache_and_possibly_refresh_it (
542
558
scopes , account , the_authority , force_refresh = force_refresh ,
543
559
correlation_id = correlation_id ,
@@ -780,13 +796,11 @@ def acquire_token_by_username_password(
780
796
781
797
def _acquire_token_by_username_password_federated (
782
798
self , user_realm_result , username , password , scopes = None , ** kwargs ):
783
- verify = kwargs .pop ("verify" , self .verify )
784
- proxies = kwargs .pop ("proxies" , self .proxies )
785
799
wstrust_endpoint = {}
786
800
if user_realm_result .get ("federation_metadata_url" ):
787
801
wstrust_endpoint = mex_send_request (
788
802
user_realm_result ["federation_metadata_url" ],
789
- verify = verify , proxies = proxies )
803
+ self . http_client )
790
804
if wstrust_endpoint is None :
791
805
raise ValueError ("Unable to find wstrust endpoint from MEX. "
792
806
"This typically happens when attempting MSA accounts. "
@@ -798,7 +812,7 @@ def _acquire_token_by_username_password_federated(
798
812
wstrust_endpoint .get ("address" ,
799
813
# Fallback to an AAD supplied endpoint
800
814
user_realm_result .get ("federation_active_auth_url" )),
801
- wstrust_endpoint .get ("action" ), verify = verify , proxies = proxies )
815
+ wstrust_endpoint .get ("action" ), self . http_client )
802
816
if not ("token" in wstrust_result and "type" in wstrust_result ):
803
817
raise RuntimeError ("Unsuccessful RSTR. %s" % wstrust_result )
804
818
GRANT_TYPE_SAML1_1 = 'urn:ietf:params:oauth:grant-type:saml1_1-bearer'
0 commit comments