From 09acd3c72e0ab49a617f0f955ad9423adb5c7876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0vihl=C3=ADk?= Date: Tue, 16 Nov 2021 13:52:31 +0100 Subject: [PATCH 1/5] identity and network traversal unified with sms --- .../identity/_shared/user_credential.py | 26 ++++------ .../identity/_shared/user_credential_async.py | 50 ++++++++++--------- .../communication/identity/_shared/utils.py | 11 +--- .../networktraversal/_shared/policy.py | 1 - .../_shared/user_credential.py | 26 ++++------ .../_shared/user_credential_async.py | 50 ++++++++++--------- .../networktraversal/_shared/utils.py | 12 +---- 7 files changed, 78 insertions(+), 98 deletions(-) diff --git a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential.py b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential.py index 9c3228b28619..9b5f17dcc95d 100644 --- a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential.py +++ b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential.py @@ -4,16 +4,16 @@ # license information. # -------------------------------------------------------------------------- from threading import Lock, Condition -from datetime import datetime, timedelta +from datetime import timedelta from typing import ( # pylint: disable=unused-import cast, Tuple, ) -from msrest.serialization import TZ_UTC - +from .utils import get_current_utc_as_int from .user_token_refresh_options import CommunicationTokenRefreshOptions + class CommunicationTokenCredential(object): """Credential type used for authenticating to an Azure Communication service. :param str token: The token used to authenticate to an Azure Communication service @@ -24,9 +24,9 @@ class CommunicationTokenCredential(object): _ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - **kwargs - ): + token, # type: str + **kwargs + ): token_refresher = kwargs.pop('token_refresher', None) communication_token_refresh_options = CommunicationTokenRefreshOptions(token=token, token_refresher=token_refresher) @@ -35,8 +35,8 @@ def __init__(self, self._lock = Condition(Lock()) self._some_thread_refreshing = False - def get_token(self): - # type () -> ~azure.core.credentials.AccessToken + def get_token(self, *scopes, **kwargs): # pylint: disable=unused-argument + # type (*str, **Any) -> AccessToken """The value of the configured token. :rtype: ~azure.core.credentials.AccessToken """ @@ -79,12 +79,8 @@ def _wait_till_inprogress_thread_finish_refreshing(self): self._lock.acquire() def _token_expiring(self): - return self._token.expires_on - self._get_utc_now() <\ - timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES) + return self._token.expires_on - get_current_utc_as_int() <\ + timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES).total_seconds() def _is_currenttoken_valid(self): - return self._get_utc_now() < self._token.expires_on - - @classmethod - def _get_utc_now(cls): - return datetime.now().replace(tzinfo=TZ_UTC) + return get_current_utc_as_int() < self._token.expires_on diff --git a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential_async.py b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential_async.py index b49c593a066d..52a99e7a4b6a 100644 --- a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential_async.py +++ b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/user_credential_async.py @@ -4,29 +4,27 @@ # license information. # -------------------------------------------------------------------------- from asyncio import Condition, Lock -from datetime import datetime, timedelta +from datetime import timedelta from typing import ( # pylint: disable=unused-import cast, Tuple, + Any ) -from msrest.serialization import TZ_UTC - +from .utils import get_current_utc_as_int from .user_token_refresh_options import CommunicationTokenRefreshOptions + class CommunicationTokenCredential(object): """Credential type used for authenticating to an Azure Communication service. :param str token: The token used to authenticate to an Azure Communication service - :keyword token_refresher: The token refresher to provide capacity to fetch fresh token + :keyword token_refresher: The async token refresher to provide capacity to fetch fresh token :raises: TypeError """ _ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 - def __init__(self, - token, # type: str - **kwargs - ): + def __init__(self, token: str, **kwargs: Any): token_refresher = kwargs.pop('token_refresher', None) communication_token_refresh_options = CommunicationTokenRefreshOptions(token=token, token_refresher=token_refresher) @@ -35,25 +33,24 @@ def __init__(self, self._lock = Condition(Lock()) self._some_thread_refreshing = False - def get_token(self): - # type () -> ~azure.core.credentials.AccessToken + async def get_token(self, *scopes, **kwargs): # pylint: disable=unused-argument + # type (*str, **Any) -> AccessToken """The value of the configured token. :rtype: ~azure.core.credentials.AccessToken """ - if not self._token_refresher or not self._token_expiring(): return self._token should_this_thread_refresh = False - with self._lock: + async with self._lock: while self._token_expiring(): if self._some_thread_refreshing: if self._is_currenttoken_valid(): return self._token - self._wait_till_inprogress_thread_finish_refreshing() + await self._wait_till_inprogress_thread_finish_refreshing() else: should_this_thread_refresh = True self._some_thread_refreshing = True @@ -62,14 +59,14 @@ def get_token(self): if should_this_thread_refresh: try: - newtoken = self._token_refresher() # pylint:disable=not-callable + newtoken = await self._token_refresher() # pylint:disable=not-callable - with self._lock: + async with self._lock: self._token = newtoken self._some_thread_refreshing = False self._lock.notify_all() except: - with self._lock: + async with self._lock: self._some_thread_refreshing = False self._lock.notify_all() @@ -77,17 +74,22 @@ def get_token(self): return self._token - def _wait_till_inprogress_thread_finish_refreshing(self): + async def _wait_till_inprogress_thread_finish_refreshing(self): self._lock.release() - self._lock.acquire() + await self._lock.acquire() def _token_expiring(self): - return self._token.expires_on - self._get_utc_now() <\ - timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES) + return self._token.expires_on - get_current_utc_as_int() <\ + timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES).total_seconds() def _is_currenttoken_valid(self): - return self._get_utc_now() < self._token.expires_on + return get_current_utc_as_int() < self._token.expires_on + + async def close(self) -> None: + pass + + async def __aenter__(self): + return self - @classmethod - def _get_utc_now(cls): - return datetime.now().replace(tzinfo=TZ_UTC) + async def __aexit__(self, *args): + await self.close() diff --git a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py index 40d605b4fc81..4da2691b9fb2 100644 --- a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py +++ b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py @@ -6,7 +6,6 @@ import base64 import json -import time from typing import ( # pylint: disable=unused-import cast, Tuple, @@ -16,6 +15,7 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken + def _convert_datetime_to_utc_int(expires_on): return int(calendar.timegm(expires_on.utctimetuple())) @@ -50,6 +50,7 @@ def get_current_utc_time(): # type: () -> str return str(datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S ")) + "GMT" + def get_current_utc_as_int(): # type: () -> int current_utc_datetime = datetime.utcnow().replace(tzinfo=TZ_UTC) @@ -83,10 +84,6 @@ def create_access_token(token): except ValueError: raise ValueError(token_parse_err_msg) -def _convert_expires_on_datetime_to_utc_int(expires_on): - epoch = time.mktime(datetime(1970, 1, 1).timetuple()) - return epoch-time.mktime(expires_on.timetuple()) - def get_authentication_policy( endpoint, # type: str credential, # type: TokenCredential or str @@ -122,7 +119,3 @@ def get_authentication_policy( raise TypeError("Unsupported credential: {}. Use an access token string to use HMACCredentialsPolicy" "or a token credential from azure.identity".format(type(credential))) - -def _convert_expires_on_datetime_to_utc_int(expires_on): - epoch = time.mktime(datetime(1970, 1, 1).timetuple()) - return epoch-time.mktime(expires_on.timetuple()) diff --git a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/policy.py b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/policy.py index 7f795372afb7..d4197ede0e38 100644 --- a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/policy.py +++ b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/policy.py @@ -20,7 +20,6 @@ def __init__(self, access_key, # type: str decode_url=False # type: bool ): - # pylint: disable=bad-option-value,useless-object-inheritance,disable=super-with-arguments # type: (...) -> None super(HMACCredentialsPolicy, self).__init__() diff --git a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential.py b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential.py index 9c3228b28619..9b5f17dcc95d 100644 --- a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential.py +++ b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential.py @@ -4,16 +4,16 @@ # license information. # -------------------------------------------------------------------------- from threading import Lock, Condition -from datetime import datetime, timedelta +from datetime import timedelta from typing import ( # pylint: disable=unused-import cast, Tuple, ) -from msrest.serialization import TZ_UTC - +from .utils import get_current_utc_as_int from .user_token_refresh_options import CommunicationTokenRefreshOptions + class CommunicationTokenCredential(object): """Credential type used for authenticating to an Azure Communication service. :param str token: The token used to authenticate to an Azure Communication service @@ -24,9 +24,9 @@ class CommunicationTokenCredential(object): _ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - **kwargs - ): + token, # type: str + **kwargs + ): token_refresher = kwargs.pop('token_refresher', None) communication_token_refresh_options = CommunicationTokenRefreshOptions(token=token, token_refresher=token_refresher) @@ -35,8 +35,8 @@ def __init__(self, self._lock = Condition(Lock()) self._some_thread_refreshing = False - def get_token(self): - # type () -> ~azure.core.credentials.AccessToken + def get_token(self, *scopes, **kwargs): # pylint: disable=unused-argument + # type (*str, **Any) -> AccessToken """The value of the configured token. :rtype: ~azure.core.credentials.AccessToken """ @@ -79,12 +79,8 @@ def _wait_till_inprogress_thread_finish_refreshing(self): self._lock.acquire() def _token_expiring(self): - return self._token.expires_on - self._get_utc_now() <\ - timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES) + return self._token.expires_on - get_current_utc_as_int() <\ + timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES).total_seconds() def _is_currenttoken_valid(self): - return self._get_utc_now() < self._token.expires_on - - @classmethod - def _get_utc_now(cls): - return datetime.now().replace(tzinfo=TZ_UTC) + return get_current_utc_as_int() < self._token.expires_on diff --git a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential_async.py b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential_async.py index b49c593a066d..52a99e7a4b6a 100644 --- a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential_async.py +++ b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/user_credential_async.py @@ -4,29 +4,27 @@ # license information. # -------------------------------------------------------------------------- from asyncio import Condition, Lock -from datetime import datetime, timedelta +from datetime import timedelta from typing import ( # pylint: disable=unused-import cast, Tuple, + Any ) -from msrest.serialization import TZ_UTC - +from .utils import get_current_utc_as_int from .user_token_refresh_options import CommunicationTokenRefreshOptions + class CommunicationTokenCredential(object): """Credential type used for authenticating to an Azure Communication service. :param str token: The token used to authenticate to an Azure Communication service - :keyword token_refresher: The token refresher to provide capacity to fetch fresh token + :keyword token_refresher: The async token refresher to provide capacity to fetch fresh token :raises: TypeError """ _ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 - def __init__(self, - token, # type: str - **kwargs - ): + def __init__(self, token: str, **kwargs: Any): token_refresher = kwargs.pop('token_refresher', None) communication_token_refresh_options = CommunicationTokenRefreshOptions(token=token, token_refresher=token_refresher) @@ -35,25 +33,24 @@ def __init__(self, self._lock = Condition(Lock()) self._some_thread_refreshing = False - def get_token(self): - # type () -> ~azure.core.credentials.AccessToken + async def get_token(self, *scopes, **kwargs): # pylint: disable=unused-argument + # type (*str, **Any) -> AccessToken """The value of the configured token. :rtype: ~azure.core.credentials.AccessToken """ - if not self._token_refresher or not self._token_expiring(): return self._token should_this_thread_refresh = False - with self._lock: + async with self._lock: while self._token_expiring(): if self._some_thread_refreshing: if self._is_currenttoken_valid(): return self._token - self._wait_till_inprogress_thread_finish_refreshing() + await self._wait_till_inprogress_thread_finish_refreshing() else: should_this_thread_refresh = True self._some_thread_refreshing = True @@ -62,14 +59,14 @@ def get_token(self): if should_this_thread_refresh: try: - newtoken = self._token_refresher() # pylint:disable=not-callable + newtoken = await self._token_refresher() # pylint:disable=not-callable - with self._lock: + async with self._lock: self._token = newtoken self._some_thread_refreshing = False self._lock.notify_all() except: - with self._lock: + async with self._lock: self._some_thread_refreshing = False self._lock.notify_all() @@ -77,17 +74,22 @@ def get_token(self): return self._token - def _wait_till_inprogress_thread_finish_refreshing(self): + async def _wait_till_inprogress_thread_finish_refreshing(self): self._lock.release() - self._lock.acquire() + await self._lock.acquire() def _token_expiring(self): - return self._token.expires_on - self._get_utc_now() <\ - timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES) + return self._token.expires_on - get_current_utc_as_int() <\ + timedelta(minutes=self._ON_DEMAND_REFRESHING_INTERVAL_MINUTES).total_seconds() def _is_currenttoken_valid(self): - return self._get_utc_now() < self._token.expires_on + return get_current_utc_as_int() < self._token.expires_on + + async def close(self) -> None: + pass + + async def __aenter__(self): + return self - @classmethod - def _get_utc_now(cls): - return datetime.now().replace(tzinfo=TZ_UTC) + async def __aexit__(self, *args): + await self.close() diff --git a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py index 332d02a59069..4da2691b9fb2 100644 --- a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py +++ b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py @@ -6,7 +6,6 @@ import base64 import json -import time from typing import ( # pylint: disable=unused-import cast, Tuple, @@ -16,6 +15,7 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken + def _convert_datetime_to_utc_int(expires_on): return int(calendar.timegm(expires_on.utctimetuple())) @@ -50,13 +50,13 @@ def get_current_utc_time(): # type: () -> str return str(datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S ")) + "GMT" + def get_current_utc_as_int(): # type: () -> int current_utc_datetime = datetime.utcnow().replace(tzinfo=TZ_UTC) return _convert_datetime_to_utc_int(current_utc_datetime) def create_access_token(token): - # pylint: disable=bad-option-value,useless-object-inheritance,raise-missing-from # type: (str) -> azure.core.credentials.AccessToken """Creates an instance of azure.core.credentials.AccessToken from a string token. The input string is jwt token in the following form: @@ -84,10 +84,6 @@ def create_access_token(token): except ValueError: raise ValueError(token_parse_err_msg) -def _convert_expires_on_datetime_to_utc_int(expires_on): - epoch = time.mktime(datetime(1970, 1, 1).timetuple()) - return epoch-time.mktime(expires_on.timetuple()) - def get_authentication_policy( endpoint, # type: str credential, # type: TokenCredential or str @@ -123,7 +119,3 @@ def get_authentication_policy( raise TypeError("Unsupported credential: {}. Use an access token string to use HMACCredentialsPolicy" "or a token credential from azure.identity".format(type(credential))) - -def _convert_expires_on_datetime_to_utc_int(expires_on): - epoch = time.mktime(datetime(1970, 1, 1).timetuple()) - return epoch-time.mktime(expires_on.timetuple()) From 42527908713c1fc3e8fedea07bebd4669259b3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0vihl=C3=ADk?= Date: Tue, 16 Nov 2021 16:29:20 +0100 Subject: [PATCH 2/5] unified get_current_utc_as_int + added a test --- .../tests/_shared/test_utils.py | 5 ++++- .../azure/communication/identity/_shared/utils.py | 11 +++++++++-- .../communication/networktraversal/_shared/utils.py | 11 +++++++++-- .../azure/communication/phonenumbers/_shared/utils.py | 11 +++++++++-- .../azure/communication/sms/_shared/utils.py | 11 +++++++++-- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py b/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py index f84d088eb282..715ee930dfe6 100644 --- a/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py +++ b/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py @@ -11,7 +11,10 @@ class UtilsTest(unittest.TestCase): def test_convert_datetime_to_utc_int(self): # UTC utc_time_in_sec = _convert_datetime_to_utc_int(datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=dateutil.tz.tzutc())) - assert utc_time_in_sec == 0 + assert utc_time_in_sec == 0 + # UTC naive (without a timezone specified) + utc_naive_time_in_sec = _convert_datetime_to_utc_int(datetime(1970, 1, 1, 0, 0, 0, 0)) + assert utc_naive_time_in_sec == 0 # PST is UTC-8 pst_time_in_sec = _convert_datetime_to_utc_int(datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=dateutil.tz.gettz('America/Vancouver'))) assert pst_time_in_sec == 8 * 3600 diff --git a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py index 4da2691b9fb2..c381975b6bff 100644 --- a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py +++ b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py @@ -15,8 +15,15 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken - def _convert_datetime_to_utc_int(expires_on): + """ + Converts DateTime in local time to the Epoch in UTC in second. + + :param input_datetime: Input datetime + :type input_datetime: datetime + :return: Integer + :rtype: int + """ return int(calendar.timegm(expires_on.utctimetuple())) def parse_connection_str(conn_str): @@ -53,7 +60,7 @@ def get_current_utc_time(): def get_current_utc_as_int(): # type: () -> int - current_utc_datetime = datetime.utcnow().replace(tzinfo=TZ_UTC) + current_utc_datetime = datetime.utcnow() return _convert_datetime_to_utc_int(current_utc_datetime) def create_access_token(token): diff --git a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py index 4da2691b9fb2..c381975b6bff 100644 --- a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py +++ b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py @@ -15,8 +15,15 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken - def _convert_datetime_to_utc_int(expires_on): + """ + Converts DateTime in local time to the Epoch in UTC in second. + + :param input_datetime: Input datetime + :type input_datetime: datetime + :return: Integer + :rtype: int + """ return int(calendar.timegm(expires_on.utctimetuple())) def parse_connection_str(conn_str): @@ -53,7 +60,7 @@ def get_current_utc_time(): def get_current_utc_as_int(): # type: () -> int - current_utc_datetime = datetime.utcnow().replace(tzinfo=TZ_UTC) + current_utc_datetime = datetime.utcnow() return _convert_datetime_to_utc_int(current_utc_datetime) def create_access_token(token): diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py index 4da2691b9fb2..c381975b6bff 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py @@ -15,8 +15,15 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken - def _convert_datetime_to_utc_int(expires_on): + """ + Converts DateTime in local time to the Epoch in UTC in second. + + :param input_datetime: Input datetime + :type input_datetime: datetime + :return: Integer + :rtype: int + """ return int(calendar.timegm(expires_on.utctimetuple())) def parse_connection_str(conn_str): @@ -53,7 +60,7 @@ def get_current_utc_time(): def get_current_utc_as_int(): # type: () -> int - current_utc_datetime = datetime.utcnow().replace(tzinfo=TZ_UTC) + current_utc_datetime = datetime.utcnow() return _convert_datetime_to_utc_int(current_utc_datetime) def create_access_token(token): diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py index 4da2691b9fb2..c381975b6bff 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py @@ -15,8 +15,15 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken - def _convert_datetime_to_utc_int(expires_on): + """ + Converts DateTime in local time to the Epoch in UTC in second. + + :param input_datetime: Input datetime + :type input_datetime: datetime + :return: Integer + :rtype: int + """ return int(calendar.timegm(expires_on.utctimetuple())) def parse_connection_str(conn_str): @@ -53,7 +60,7 @@ def get_current_utc_time(): def get_current_utc_as_int(): # type: () -> int - current_utc_datetime = datetime.utcnow().replace(tzinfo=TZ_UTC) + current_utc_datetime = datetime.utcnow() return _convert_datetime_to_utc_int(current_utc_datetime) def create_access_token(token): From 191dc6284e424035c9f4c4ae5f48f234d2054074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0vihl=C3=ADk?= Date: Fri, 19 Nov 2021 11:16:39 +0100 Subject: [PATCH 3/5] adjusted variable name to match the comment --- .../azure/communication/chat/_shared/utils.py | 4 ++-- .../azure/communication/identity/_shared/utils.py | 4 ++-- .../azure/communication/networktraversal/_shared/utils.py | 4 ++-- .../azure/communication/phonenumbers/_shared/utils.py | 4 ++-- .../azure/communication/sms/_shared/utils.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py index c381975b6bff..5951a280e771 100644 --- a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py +++ b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py @@ -15,7 +15,7 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken -def _convert_datetime_to_utc_int(expires_on): +def _convert_datetime_to_utc_int(input_datetime): """ Converts DateTime in local time to the Epoch in UTC in second. @@ -24,7 +24,7 @@ def _convert_datetime_to_utc_int(expires_on): :return: Integer :rtype: int """ - return int(calendar.timegm(expires_on.utctimetuple())) + return int(calendar.timegm(input_datetime.utctimetuple())) def parse_connection_str(conn_str): # type: (str) -> Tuple[str, str, str, str] diff --git a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py index c381975b6bff..5951a280e771 100644 --- a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py +++ b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py @@ -15,7 +15,7 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken -def _convert_datetime_to_utc_int(expires_on): +def _convert_datetime_to_utc_int(input_datetime): """ Converts DateTime in local time to the Epoch in UTC in second. @@ -24,7 +24,7 @@ def _convert_datetime_to_utc_int(expires_on): :return: Integer :rtype: int """ - return int(calendar.timegm(expires_on.utctimetuple())) + return int(calendar.timegm(input_datetime.utctimetuple())) def parse_connection_str(conn_str): # type: (str) -> Tuple[str, str, str, str] diff --git a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py index c381975b6bff..5951a280e771 100644 --- a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py +++ b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py @@ -15,7 +15,7 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken -def _convert_datetime_to_utc_int(expires_on): +def _convert_datetime_to_utc_int(input_datetime): """ Converts DateTime in local time to the Epoch in UTC in second. @@ -24,7 +24,7 @@ def _convert_datetime_to_utc_int(expires_on): :return: Integer :rtype: int """ - return int(calendar.timegm(expires_on.utctimetuple())) + return int(calendar.timegm(input_datetime.utctimetuple())) def parse_connection_str(conn_str): # type: (str) -> Tuple[str, str, str, str] diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py index c381975b6bff..5951a280e771 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py @@ -15,7 +15,7 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken -def _convert_datetime_to_utc_int(expires_on): +def _convert_datetime_to_utc_int(input_datetime): """ Converts DateTime in local time to the Epoch in UTC in second. @@ -24,7 +24,7 @@ def _convert_datetime_to_utc_int(expires_on): :return: Integer :rtype: int """ - return int(calendar.timegm(expires_on.utctimetuple())) + return int(calendar.timegm(input_datetime.utctimetuple())) def parse_connection_str(conn_str): # type: (str) -> Tuple[str, str, str, str] diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py index c381975b6bff..5951a280e771 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py @@ -15,7 +15,7 @@ from msrest.serialization import TZ_UTC from azure.core.credentials import AccessToken -def _convert_datetime_to_utc_int(expires_on): +def _convert_datetime_to_utc_int(input_datetime): """ Converts DateTime in local time to the Epoch in UTC in second. @@ -24,7 +24,7 @@ def _convert_datetime_to_utc_int(expires_on): :return: Integer :rtype: int """ - return int(calendar.timegm(expires_on.utctimetuple())) + return int(calendar.timegm(input_datetime.utctimetuple())) def parse_connection_str(conn_str): # type: (str) -> Tuple[str, str, str, str] From bbaff7683367ad959041a9034c32c4e3a510f29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0vihl=C3=ADk?= Date: Fri, 26 Nov 2021 17:03:35 +0100 Subject: [PATCH 4/5] added owners to enforce reviews --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c387bea59c01..49ee992b270d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -42,6 +42,7 @@ /sdk/communication/azure-communication-phonenumbers/ @RoyHerrod @danielav7 @whisper6284 @AlonsoMondal /sdk/communication/azure-communication-sms/ @RoyHerrod @arifibrahim4 /sdk/communication/azure-communication-identity/ @Azure/acs-identity-sdk +/sdk/communication/**/_shared/ @Azure/acs-identity-sdk # PRLabel: %KeyVault /sdk/keyvault/ @schaabs @chlowell @mccoyp @YalinLi0312 From 5371ea77a103c37a12df9c6e712761fc102e42c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0vihl=C3=ADk?= Date: Mon, 29 Nov 2021 08:10:23 +0100 Subject: [PATCH 5/5] token deserialization fix + test --- .../azure/communication/chat/_shared/utils.py | 2 +- .../tests/_shared/test_utils.py | 23 +++++++++++++++++++ .../communication/identity/_shared/utils.py | 2 +- .../networktraversal/_shared/utils.py | 2 +- .../phonenumbers/_shared/utils.py | 2 +- .../azure/communication/sms/_shared/utils.py | 2 +- 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py index 5951a280e771..c9255a4217d7 100644 --- a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py +++ b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/utils.py @@ -87,7 +87,7 @@ def create_access_token(token): padded_base64_payload = base64.b64decode(parts[1] + "==").decode('ascii') payload = json.loads(padded_base64_payload) return AccessToken(token, - _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp']).replace(tzinfo=TZ_UTC))) + _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp'], TZ_UTC))) except ValueError: raise ValueError(token_parse_err_msg) diff --git a/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py b/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py index 715ee930dfe6..61e9df6d5ba9 100644 --- a/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py +++ b/sdk/communication/azure-communication-chat/tests/_shared/test_utils.py @@ -1,6 +1,9 @@ import unittest from datetime import datetime +from azure.communication.chat._shared.utils import create_access_token +from azure.communication.chat._shared.utils import get_current_utc_as_int import dateutil.tz +import base64 from azure.communication.chat._shared.utils import( _convert_datetime_to_utc_int @@ -8,6 +11,15 @@ class UtilsTest(unittest.TestCase): + @staticmethod + def get_token_with_custom_expiry(expires_on): + expiry_json = '{"exp": ' + str(expires_on) + '}' + base64expiry = base64.b64encode( + expiry_json.encode('utf-8')).decode('utf-8').rstrip("=") + token_template = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +\ + base64expiry + ".adM-ddBZZlQ1WlN3pdPBOF5G4Wh9iZpxNP_fSvpF4cWs" + return token_template + def test_convert_datetime_to_utc_int(self): # UTC utc_time_in_sec = _convert_datetime_to_utc_int(datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=dateutil.tz.tzutc())) @@ -25,5 +37,16 @@ def test_convert_datetime_to_utc_int(self): cst_time_in_sec = _convert_datetime_to_utc_int(datetime(1970, 1, 1, 0, 0, 0, 0, tzinfo=dateutil.tz.gettz('Asia/Shanghai'))) assert cst_time_in_sec == -8 * 3600 + + def test_access_token_expiry_deserialized_correctly_from_payload(self): + start_timestamp = get_current_utc_as_int() + token_validity_minutes = 60 + token_expiry = start_timestamp + token_validity_minutes * 60 + + token = create_access_token( + self.get_token_with_custom_expiry(token_expiry)) + + self.assertEqual(token.expires_on, token_expiry) + if __name__ == "__main__": unittest.main() diff --git a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py index 5951a280e771..c9255a4217d7 100644 --- a/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py +++ b/sdk/communication/azure-communication-identity/azure/communication/identity/_shared/utils.py @@ -87,7 +87,7 @@ def create_access_token(token): padded_base64_payload = base64.b64decode(parts[1] + "==").decode('ascii') payload = json.loads(padded_base64_payload) return AccessToken(token, - _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp']).replace(tzinfo=TZ_UTC))) + _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp'], TZ_UTC))) except ValueError: raise ValueError(token_parse_err_msg) diff --git a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py index 5951a280e771..c9255a4217d7 100644 --- a/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py +++ b/sdk/communication/azure-communication-networktraversal/azure/communication/networktraversal/_shared/utils.py @@ -87,7 +87,7 @@ def create_access_token(token): padded_base64_payload = base64.b64decode(parts[1] + "==").decode('ascii') payload = json.loads(padded_base64_payload) return AccessToken(token, - _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp']).replace(tzinfo=TZ_UTC))) + _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp'], TZ_UTC))) except ValueError: raise ValueError(token_parse_err_msg) diff --git a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py index 5951a280e771..c9255a4217d7 100644 --- a/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py +++ b/sdk/communication/azure-communication-phonenumbers/azure/communication/phonenumbers/_shared/utils.py @@ -87,7 +87,7 @@ def create_access_token(token): padded_base64_payload = base64.b64decode(parts[1] + "==").decode('ascii') payload = json.loads(padded_base64_payload) return AccessToken(token, - _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp']).replace(tzinfo=TZ_UTC))) + _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp'], TZ_UTC))) except ValueError: raise ValueError(token_parse_err_msg) diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py index 5951a280e771..c9255a4217d7 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/utils.py @@ -87,7 +87,7 @@ def create_access_token(token): padded_base64_payload = base64.b64decode(parts[1] + "==").decode('ascii') payload = json.loads(padded_base64_payload) return AccessToken(token, - _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp']).replace(tzinfo=TZ_UTC))) + _convert_datetime_to_utc_int(datetime.fromtimestamp(payload['exp'], TZ_UTC))) except ValueError: raise ValueError(token_parse_err_msg)