Skip to content

Commit ee2b4e0

Browse files
committed
Support ISO8601-ish format on expires_on in MI
1 parent 4db4a8c commit ee2b4e0

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

msal/managed_identity.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
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
10+
import re
811
import socket
912
import sys
1013
import time
@@ -432,6 +435,35 @@ def _obtain_token(http_client, managed_identity, resource):
432435
return _obtain_token_on_azure_vm(http_client, managed_identity, resource)
433436

434437

438+
def _parse_expires_on(raw: str) -> int:
439+
try:
440+
return int(raw) # It is typically an epoch time
441+
except ValueError:
442+
pass
443+
try:
444+
# '2024-10-18T19:51:37.0000000+00:00' was observed in
445+
# https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/4963
446+
if sys.version_info < (3, 11): # Does not support 7-digit microseconds
447+
raw = re.sub( # Strip microseconds portion using regex
448+
r'(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(\.\d+)([+-]\d{2}:\d{2})',
449+
r'\1\3',
450+
raw)
451+
return int(datetime.datetime.fromisoformat(raw).timestamp())
452+
except ValueError:
453+
pass
454+
for format in (
455+
"%m/%d/%Y %H:%M:%S %z", # Support "06/20/2019 02:57:58 +00:00"
456+
# 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
457+
"%m/%d/%Y %I:%M:%S %p %z", # Support "1/16/2020 12:0:12 AM +00:00"
458+
# 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
459+
):
460+
try:
461+
return calendar.timegm(time.strptime(raw, format))
462+
except ValueError:
463+
pass
464+
raise ManagedIdentityError(f"Cannot parse expires_on: {raw}")
465+
466+
435467
def _adjust_param(params, managed_identity, types_mapping=None):
436468
# Modify the params dict in place
437469
id_name = (types_mapping or ManagedIdentity._types_mapping).get(
@@ -504,7 +536,7 @@ def _obtain_token_on_app_service(
504536
if payload.get("access_token") and payload.get("expires_on"):
505537
return { # Normalizing the payload into OAuth2 format
506538
"access_token": payload["access_token"],
507-
"expires_in": int(payload["expires_on"]) - int(time.time()),
539+
"expires_in": _parse_expires_on(payload["expires_on"]) - int(time.time()),
508540
"resource": payload.get("resource"),
509541
"token_type": payload.get("token_type", "Bearer"),
510542
}
@@ -538,7 +570,7 @@ def _obtain_token_on_machine_learning(
538570
if payload.get("access_token") and payload.get("expires_on"):
539571
return { # Normalizing the payload into OAuth2 format
540572
"access_token": payload["access_token"],
541-
"expires_in": int(payload["expires_on"]) - int(time.time()),
573+
"expires_in": _parse_expires_on(payload["expires_on"]) - int(time.time()),
542574
"resource": payload.get("resource"),
543575
"token_type": payload.get("token_type", "Bearer"),
544576
}

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)