Skip to content

Commit 2345ca8

Browse files
committed
Support ISO8601-ish format on expires_on in MI
1 parent 137dee4 commit 2345ca8

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

msal/managed_identity.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
# All rights reserved.
33
#
44
# This code is licensed under the MIT License.
5+
import calendar
6+
import datetime
57
import json
68
import logging
79
import os
@@ -432,6 +434,29 @@ def _obtain_token(http_client, managed_identity, resource):
432434
return _obtain_token_on_azure_vm(http_client, managed_identity, resource)
433435

434436

437+
def _parse_expires_on(raw: str) -> int:
438+
try:
439+
return int(raw) # It is typically an epoch time
440+
except ValueError:
441+
pass
442+
try:
443+
# '2024-10-18T19:51:37.0000000+00:00' was observed in
444+
# https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/4963
445+
# We support format(s) YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]]
446+
return int(datetime.datetime.fromisoformat(raw).timestamp())
447+
except ValueError:
448+
pass
449+
for format in (
450+
"%m/%d/%Y %H:%M:%S %z", # Derived from https://github.com/Azure/azure-sdk-for-python/blob/azure-identity_1.21.0/sdk/identity/azure-identity/azure/identity/_credentials/azure_ml.py#L52
451+
"%m/%d/%Y %I:%M:%S %p %z", # Derived from https://github.com/Azure/azure-sdk-for-python/blob/azure-identity_1.21.0/sdk/identity/azure-identity/azure/identity/_credentials/azure_ml.py#L51
452+
):
453+
try:
454+
return calendar.timegm(time.strptime(raw, format))
455+
except ValueError:
456+
pass
457+
raise ManagedIdentityError(f"Cannot parse expires_on: {raw}")
458+
459+
435460
def _adjust_param(params, managed_identity, types_mapping=None):
436461
# Modify the params dict in place
437462
id_name = (types_mapping or ManagedIdentity._types_mapping).get(
@@ -504,7 +529,7 @@ def _obtain_token_on_app_service(
504529
if payload.get("access_token") and payload.get("expires_on"):
505530
return { # Normalizing the payload into OAuth2 format
506531
"access_token": payload["access_token"],
507-
"expires_in": int(payload["expires_on"]) - int(time.time()),
532+
"expires_in": _parse_expires_on(payload["expires_on"]) - int(time.time()),
508533
"resource": payload.get("resource"),
509534
"token_type": payload.get("token_type", "Bearer"),
510535
}
@@ -538,7 +563,7 @@ def _obtain_token_on_machine_learning(
538563
if payload.get("access_token") and payload.get("expires_on"):
539564
return { # Normalizing the payload into OAuth2 format
540565
"access_token": payload["access_token"],
541-
"expires_in": int(payload["expires_on"]) - int(time.time()),
566+
"expires_in": _parse_expires_on(payload["expires_on"]) - int(time.time()),
542567
"resource": payload.get("resource"),
543568
"token_type": payload.get("token_type", "Bearer"),
544569
}

tests/test_mi.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
MACHINE_LEARNING,
2626
SERVICE_FABRIC,
2727
DEFAULT_TO_VM,
28+
_parse_expires_on,
2829
)
2930
from msal.token_cache import is_subdict_of
3031

@@ -49,6 +50,21 @@ def test_helper_class_should_be_interchangable_with_dict_which_could_be_loaded_f
4950
{"ManagedIdentityIdType": "SystemAssigned", "Id": None})
5051

5152

53+
class ExpiresOnTestCase(unittest.TestCase):
54+
def test_expires_on_parsing(self):
55+
for input, epoch in {
56+
"1234567890": 1234567890,
57+
"1970-01-01T00:00:12.0000000+00:00": 12,
58+
"2024-10-18T19:51:37.0000000+00:00": 1729281097, # Copied from https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/4963
59+
"01/01/1970 00:00:12 +00:00": 12,
60+
"06/20/2019 02:57:58 +00:00": 1560999478, # Derived from https://github.com/Azure/azure-sdk-for-python/blob/azure-identity_1.21.0/sdk/identity/azure-identity/azure/identity/_credentials/azure_ml.py#L52
61+
"1/1/1970 12:0:12 AM +00:00": 12,
62+
"1/1/1970 12:0:12 PM +00:00": 43212,
63+
"1/16/2020 5:24:12 AM +00:00": 1579152252, # Derived from https://github.com/Azure/azure-sdk-for-python/blob/azure-identity_1.21.0/sdk/identity/azure-identity/azure/identity/_credentials/azure_ml.py#L51
64+
}.items():
65+
self.assertEqual(_parse_expires_on(input), epoch, f'Should parse "{input}" to {epoch}')
66+
67+
5268
class ClientTestCase(unittest.TestCase):
5369
maxDiff = None
5470

0 commit comments

Comments
 (0)