Skip to content

Commit b0f3299

Browse files
committed
Only call IMDS when input region != None
1 parent c2e9899 commit b0f3299

File tree

3 files changed

+42
-20
lines changed

3 files changed

+42
-20
lines changed

msal/application.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,22 @@ def __init__(
232232
:param str region:
233233
Added since MSAL Python 1.12.0.
234234
235-
If enabled, MSAL token requests would remain inside that region.
236-
Currently, regional endpoint only supports using
237-
``acquire_token_for_client()`` for some scopes.
235+
As of 2021 May, regional service is only available for
236+
``acquire_token_for_client()`` sent by any of the following scenarios::
238237
239-
The default value is None, which means region support remains turned off.
238+
1. An app powered by a capable MSAL
239+
(MSAL Python 1.12+ will be provisioned)
240+
241+
2. An app with managed identity, which is formerly known as MSI.
242+
(However MSAL Python does not support managed identity,
243+
so this one does not apply.)
244+
245+
3. An app authenticated by Subject Name/Issuer (SNI).
246+
247+
4. An app which already onboard to the region's allow-list.
248+
249+
MSAL's default value is None, which means region behavior remains off.
250+
If enabled, some of the MSAL traffic would remain inside that region.
240251
241252
App developer can opt in to regional endpoint,
242253
by provide a region name, such as "westus", "eastus2".
@@ -261,7 +272,7 @@ def __init__(
261272
# Requests, does not support session - wide timeout
262273
# But you can patch that (https://github.com/psf/requests/issues/3341):
263274
self.http_client.request = functools.partial(
264-
self.http_client.request, timeout=timeout or 2)
275+
self.http_client.request, timeout=timeout)
265276

266277
# Enable a minimal retry. Better than nothing.
267278
# https://github.com/psf/requests/blob/v2.25.1/requests/adapters.py#L94-L108
@@ -291,11 +302,15 @@ def _build_telemetry_context(
291302
correlation_id=correlation_id, refresh_reason=refresh_reason)
292303

293304
def _get_regional_authority(self, central_authority):
294-
self._region_detected = self._region_detected or _detect_region(self.http_client)
295-
if self._region_configured and self._region_detected != self._region_configured:
305+
is_region_specified = bool(self._region_configured
306+
and self._region_configured != self.ATTEMPT_REGION_DISCOVERY)
307+
self._region_detected = self._region_detected or _detect_region(
308+
self.http_client if self._region_configured is not None else None)
309+
if (is_region_specified and self._region_configured != self._region_detected):
296310
logger.warning('Region configured ({}) != region detected ({})'.format(
297311
repr(self._region_configured), repr(self._region_detected)))
298-
region_to_use = self._region_configured or self._region_detected
312+
region_to_use = (
313+
self._region_configured if is_region_specified else self._region_detected)
299314
if region_to_use:
300315
logger.info('Region to be used: {}'.format(repr(region_to_use)))
301316
regional_host = ("{}.login.microsoft.com".format(region_to_use)

msal/region.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
logger = logging.getLogger(__name__)
66

77

8-
def _detect_region(http_client):
9-
return _detect_region_of_azure_function() or _detect_region_of_azure_vm(http_client)
8+
def _detect_region(http_client=None):
9+
region = _detect_region_of_azure_function() # It is cheap, so we do it always
10+
if http_client and not region:
11+
return _detect_region_of_azure_vm(http_client) # It could hang for minutes
12+
return region
1013

1114

1215
def _detect_region_of_azure_function():
@@ -15,11 +18,15 @@ def _detect_region_of_azure_function():
1518

1619
def _detect_region_of_azure_vm(http_client):
1720
url = "http://169.254.169.254/metadata/instance?api-version=2021-01-01"
21+
logger.info(
22+
"Connecting to IMDS {}. "
23+
"You may want to use a shorter timeout on your http_client".format(url))
1824
try:
1925
# https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#instance-metadata
2026
resp = http_client.get(url, headers={"Metadata": "true"})
2127
except:
22-
logger.info("IMDS {} unavailable. Perhaps not running in Azure VM?".format(url))
28+
logger.info(
29+
"IMDS {} unavailable. Perhaps not running in Azure VM?".format(url))
2330
return None
2431
else:
2532
return json.loads(resp.text)["compute"]["location"]

tests/test_e2e.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def _get_app_and_auth_code(
2727
app = msal.ConfidentialClientApplication(
2828
client_id,
2929
client_credential=client_secret,
30-
authority=authority, http_client=MinimalHttpClient(timeout=2))
30+
authority=authority, http_client=MinimalHttpClient())
3131
else:
3232
app = msal.PublicClientApplication(
3333
client_id, authority=authority, http_client=MinimalHttpClient())
@@ -292,7 +292,7 @@ def test_client_secret(self):
292292
self.config["client_id"],
293293
client_credential=self.config.get("client_secret"),
294294
authority=self.config.get("authority"),
295-
http_client=MinimalHttpClient(timeout=2))
295+
http_client=MinimalHttpClient())
296296
scope = self.config.get("scope", [])
297297
result = self.app.acquire_token_for_client(scope)
298298
self.assertIn('access_token', result)
@@ -307,7 +307,7 @@ def test_client_certificate(self):
307307
self.app = msal.ConfidentialClientApplication(
308308
self.config['client_id'],
309309
{"private_key": private_key, "thumbprint": client_cert["thumbprint"]},
310-
http_client=MinimalHttpClient(timeout=2))
310+
http_client=MinimalHttpClient())
311311
scope = self.config.get("scope", [])
312312
result = self.app.acquire_token_for_client(scope)
313313
self.assertIn('access_token', result)
@@ -330,7 +330,7 @@ def test_subject_name_issuer_authentication(self):
330330
"thumbprint": self.config["thumbprint"],
331331
"public_certificate": public_certificate,
332332
},
333-
http_client=MinimalHttpClient(timeout=2))
333+
http_client=MinimalHttpClient())
334334
scope = self.config.get("scope", [])
335335
result = self.app.acquire_token_for_client(scope)
336336
self.assertIn('access_token', result)
@@ -379,7 +379,7 @@ def get_lab_app(
379379
client_id,
380380
client_credential=client_secret,
381381
authority=authority,
382-
http_client=MinimalHttpClient(timeout=2),
382+
http_client=MinimalHttpClient(),
383383
**kwargs)
384384

385385
def get_session(lab_app, scopes): # BTW, this infrastructure tests the confidential client flow
@@ -528,7 +528,7 @@ def _test_acquire_token_obo(self, config_pca, config_cca):
528528
config_cca["client_id"],
529529
client_credential=config_cca["client_secret"],
530530
authority=config_cca["authority"],
531-
http_client=MinimalHttpClient(timeout=2),
531+
http_client=MinimalHttpClient(),
532532
# token_cache= ..., # Default token cache is all-tokens-store-in-memory.
533533
# That's fine if OBO app uses short-lived msal instance per session.
534534
# Otherwise, the OBO app need to implement a one-cache-per-user setup.
@@ -556,7 +556,7 @@ def _test_acquire_token_by_client_secret(
556556
assert client_id and client_secret and authority and scope
557557
app = msal.ConfidentialClientApplication(
558558
client_id, client_credential=client_secret, authority=authority,
559-
http_client=MinimalHttpClient(timeout=2))
559+
http_client=MinimalHttpClient())
560560
result = app.acquire_token_for_client(scope)
561561
self.assertIsNotNone(result.get("access_token"), "Got %s instead" % result)
562562

@@ -758,7 +758,7 @@ def test_acquire_token_for_client_should_hit_regional_endpoint(self):
758758
scopes = ["https://graph.microsoft.com/.default"]
759759
result = self.app.acquire_token_for_client(
760760
scopes,
761-
params={"AllowEstsRNonMsi": "true"}, # For testing regional endpoint
761+
params={"AllowEstsRNonMsi": "true"}, # For testing regional endpoint. It will be removed once MSAL Python 1.12+ has been onboard to ESTS-R
762762
)
763763
self.assertIn('access_token', result)
764764
self.assertCacheWorksForApp(result, scopes)
@@ -855,7 +855,7 @@ def test_acquire_token_silent_with_an_empty_cache_should_return_none(self):
855855
usertype="cloud", azureenvironment=self.environment, publicClient="no")
856856
app = msal.ConfidentialClientApplication(
857857
config['client_id'], authority=config['authority'],
858-
http_client=MinimalHttpClient(timeout=2))
858+
http_client=MinimalHttpClient())
859859
result = app.acquire_token_silent(scopes=config['scope'], account=None)
860860
self.assertEqual(result, None)
861861
# Note: An alias in this region is no longer accepting HTTPS traffic.

0 commit comments

Comments
 (0)