diff --git a/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential.py b/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential.py index 73b494b8ccf3..e920d356a518 100644 --- a/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential.py +++ b/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential.py @@ -9,27 +9,22 @@ cast, Tuple, ) -import six + from msrest.serialization import TZ_UTC -from .utils import create_access_token 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 - :raises: TypeError + :param communication_token_refresh_options: The token used to authenticate to an Azure Communication service + :type communication_token_refresh_options: ~azure.communication.chat.CommunicationTokenRefreshOptions """ ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - token_refresher=None + communication_token_refresh_options ): - # type: (str) -> None - if not isinstance(token, six.string_types): - raise TypeError("token must be a string.") - self._token = create_access_token(token) - self._token_refresher = token_refresher + self._token = communication_token_refresh_options.get_token() + self._token_refresher = communication_token_refresh_options.get_token_refresher() self._lock = Condition(Lock()) self._some_thread_refreshing = False @@ -70,7 +65,6 @@ def get_token(self): self._lock.notify_all() raise - return self._token def _wait_till_inprogress_thread_finish_refreshing(self): diff --git a/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential_async.py b/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential_async.py index 710c9948c839..0918074eb04a 100644 --- a/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential_async.py +++ b/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_credential_async.py @@ -9,27 +9,23 @@ cast, Tuple, ) -import six + from msrest.serialization import TZ_UTC -from .utils import create_access_token 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 + :param communication_token_refresh_options: The token used to authenticate to an Azure Communication service + :type communication_token_refresh_options: ~azure.communication.chat.aio.CommunicationTokenRefreshOptions :raises: TypeError """ ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - token_refresher=None + communication_token_refresh_options ): - # type: (str) -> None - if not isinstance(token, six.string_types): - raise TypeError("token must be a string.") - self._token = create_access_token(token) - self._token_refresher = token_refresher + self._token = communication_token_refresh_options.get_token() + self._token_refresher = communication_token_refresh_options.get_token_refresher() self._lock = Condition(Lock()) self._some_thread_refreshing = False diff --git a/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_token_refresh_options.py b/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_token_refresh_options.py new file mode 100644 index 000000000000..6bdc0d456026 --- /dev/null +++ b/sdk/communication/azure-communication-administration/azure/communication/administration/_shared/user_token_refresh_options.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import ( # pylint: disable=unused-import + cast, + Tuple, +) +import six +from .utils import create_access_token + +class CommunicationTokenRefreshOptions(object): + """Options for refreshing CommunicationTokenCredential. + :param str token: The token used to authenticate to an Azure Communication service + :param token_refresher: The token refresher to provide capacity to fetch fresh token + :raises: TypeError + """ + + def __init__(self, + token, # type: str + token_refresher=None + ): + # type: (str) -> None + if not isinstance(token, six.string_types): + raise TypeError("token must be a string.") + self._token = token + self._token_refresher = token_refresher + + def get_token(self): + """Return the the serialized JWT token.""" + return create_access_token(self._token) + + def get_token_refresher(self): + """Return the token refresher to provide capacity to fetch fresh token.""" + return self._token_refresher diff --git a/sdk/communication/azure-communication-administration/tests/user_credential_tests.py b/sdk/communication/azure-communication-administration/tests/user_credential_tests.py index c63cfcd1434e..127e89cd6e31 100644 --- a/sdk/communication/azure-communication-administration/tests/user_credential_tests.py +++ b/sdk/communication/azure-communication-administration/tests/user_credential_tests.py @@ -6,6 +6,7 @@ from unittest import TestCase from unittest.mock import MagicMock from azure.communication.administration._shared.user_credential import CommunicationTokenCredential +from azure.communication.administration._shared.user_token_refresh_options import CommunicationTokenRefreshOptions from azure.communication.administration._shared.utils import create_access_token @@ -18,24 +19,29 @@ class TestCommunicationTokenCredential(TestCase): def test_communicationtokencredential_decodes_token(self): - credential = CommunicationTokenCredential(self.sample_token) + refresh_options = CommunicationTokenRefreshOptions(self.sample_token) + credential = CommunicationTokenCredential(refresh_options) access_token = credential.get_token() self.assertEqual(access_token.token, self.sample_token) def test_communicationtokencredential_throws_if_invalid_token(self): - self.assertRaises(ValueError, lambda: CommunicationTokenCredential("foo.bar.tar")) + refresh_options = CommunicationTokenRefreshOptions("foo.bar.tar") + self.assertRaises(ValueError, lambda: CommunicationTokenCredential(refresh_options)) def test_communicationtokencredential_throws_if_nonstring_token(self): - self.assertRaises(TypeError, lambda: CommunicationTokenCredential(454)) + refresh_options = CommunicationTokenRefreshOptions(454): + self.assertRaises(TypeError, lambda: CommunicationTokenCredential(refresh_options) def test_communicationtokencredential_static_token_returns_expired_token(self): - credential = CommunicationTokenCredential(self.expired_token) + refresh_options = CommunicationTokenRefreshOptions(self.expired_token) + credential = CommunicationTokenCredential(refresh_options) self.assertEqual(credential.get_token().token, self.expired_token) def test_communicationtokencredential_token_expired_refresh_called(self): refresher = MagicMock(return_value=self.sample_token) + refresh_options = CommunicationTokenRefreshOptions(self.sample_token, refresher) access_token = CommunicationTokenCredential( self.expired_token, token_refresher=refresher).get_token() @@ -45,9 +51,8 @@ def test_communicationtokencredential_token_expired_refresh_called(self): def test_communicationtokencredential_token_expired_refresh_called_asnecessary(self): refresher = MagicMock(return_value=create_access_token(self.expired_token)) - credential = CommunicationTokenCredential( - self.expired_token, - token_refresher=refresher) + refresh_options = CommunicationTokenRefreshOptions(self.expired_token, refresher) + credential = CommunicationTokenCredential(refresh_options) credential.get_token() access_token = credential.get_token() diff --git a/sdk/communication/azure-communication-chat/README.md b/sdk/communication/azure-communication-chat/README.md index 4fa675911338..9f825335ffaa 100644 --- a/sdk/communication/azure-communication-chat/README.md +++ b/sdk/communication/azure-communication-chat/README.md @@ -48,7 +48,8 @@ from azure.communication.chat import ChatClient, CommunicationTokenCredential # Your unique Azure Communication service endpoint endpoint = "https://.communcationservices.azure.com" token = "" -chat_client = ChatClient(endpoint, CommunicationTokenCredential(token)) +refresh_options = CommunicationTokenRefreshOptions(token) +chat_client = ChatClient(endpoint, CommunicationTokenCredential(refresh_options)) ``` ## Create Chat Thread Client diff --git a/sdk/communication/azure-communication-chat/azure/communication/chat/__init__.py b/sdk/communication/azure-communication-chat/azure/communication/chat/__init__.py index 78575fcb80c7..0e33c4caa201 100644 --- a/sdk/communication/azure-communication-chat/azure/communication/chat/__init__.py +++ b/sdk/communication/azure-communication-chat/azure/communication/chat/__init__.py @@ -7,6 +7,7 @@ ChatThreadInfo, ) from ._shared.user_credential import CommunicationTokenCredential +from ._shared.user_token_refresh_options import CommunicationTokenRefreshOptions from ._models import ( ChatThreadMember, ChatMessage, @@ -25,6 +26,7 @@ 'ChatThread', 'ChatThreadInfo', 'CommunicationTokenCredential', + 'CommunicationTokenRefreshOptions', 'ChatThreadMember', 'CommunicationUserIdentifier', ] diff --git a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential.py b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential.py index a197b98ab620..e920d356a518 100644 --- a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential.py +++ b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential.py @@ -9,28 +9,22 @@ cast, Tuple, ) -import six from msrest.serialization import TZ_UTC -from .utils import create_access_token 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 - :raises: TypeError + :param communication_token_refresh_options: The token used to authenticate to an Azure Communication service + :type communication_token_refresh_options: ~azure.communication.chat.CommunicationTokenRefreshOptions """ ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - token_refresher=None + communication_token_refresh_options ): - # type: (str) -> None - if not isinstance(token, six.string_types): - raise TypeError("token must be a string.") - self._token = create_access_token(token) - self._token_refresher = token_refresher + self._token = communication_token_refresh_options.get_token() + self._token_refresher = communication_token_refresh_options.get_token_refresher() self._lock = Condition(Lock()) self._some_thread_refreshing = False diff --git a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential_async.py b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential_async.py index ad12c37e3450..0918074eb04a 100644 --- a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential_async.py +++ b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_credential_async.py @@ -10,28 +10,22 @@ Tuple, ) -import six - from msrest.serialization import TZ_UTC -from .utils import create_access_token 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 + :param communication_token_refresh_options: The token used to authenticate to an Azure Communication service + :type communication_token_refresh_options: ~azure.communication.chat.aio.CommunicationTokenRefreshOptions :raises: TypeError """ ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - token_refresher=None + communication_token_refresh_options ): - # type: (str) -> None - if not isinstance(token, six.string_types): - raise TypeError("token must be a string.") - self._token = create_access_token(token) - self._token_refresher = token_refresher + self._token = communication_token_refresh_options.get_token() + self._token_refresher = communication_token_refresh_options.get_token_refresher() self._lock = Condition(Lock()) self._some_thread_refreshing = False diff --git a/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_token_refresh_options.py b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_token_refresh_options.py new file mode 100644 index 000000000000..6bdc0d456026 --- /dev/null +++ b/sdk/communication/azure-communication-chat/azure/communication/chat/_shared/user_token_refresh_options.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import ( # pylint: disable=unused-import + cast, + Tuple, +) +import six +from .utils import create_access_token + +class CommunicationTokenRefreshOptions(object): + """Options for refreshing CommunicationTokenCredential. + :param str token: The token used to authenticate to an Azure Communication service + :param token_refresher: The token refresher to provide capacity to fetch fresh token + :raises: TypeError + """ + + def __init__(self, + token, # type: str + token_refresher=None + ): + # type: (str) -> None + if not isinstance(token, six.string_types): + raise TypeError("token must be a string.") + self._token = token + self._token_refresher = token_refresher + + def get_token(self): + """Return the the serialized JWT token.""" + return create_access_token(self._token) + + def get_token_refresher(self): + """Return the token refresher to provide capacity to fetch fresh token.""" + return self._token_refresher diff --git a/sdk/communication/azure-communication-chat/azure/communication/chat/aio/__init__.py b/sdk/communication/azure-communication-chat/azure/communication/chat/aio/__init__.py index dfda78b4aafd..0cdbb1f11b3c 100644 --- a/sdk/communication/azure-communication-chat/azure/communication/chat/aio/__init__.py +++ b/sdk/communication/azure-communication-chat/azure/communication/chat/aio/__init__.py @@ -5,9 +5,11 @@ from ._chat_client_async import ChatClient from ._chat_thread_client_async import ChatThreadClient from .._shared.user_credential_async import CommunicationTokenCredential +from .._shared.user_token_refresh_options import CommunicationTokenRefreshOptions __all__ = [ "ChatClient", "ChatThreadClient", - "CommunicationTokenCredential" + "CommunicationTokenCredential", + "CommunicationTokenRefreshOptions" ] diff --git a/sdk/communication/azure-communication-chat/samples/chat_client_sample.py b/sdk/communication/azure-communication-chat/samples/chat_client_sample.py index 9bb0a44ae62f..ec6746fb2120 100644 --- a/sdk/communication/azure-communication-chat/samples/chat_client_sample.py +++ b/sdk/communication/azure-communication-chat/samples/chat_client_sample.py @@ -45,8 +45,9 @@ class ChatClientSamples(object): def create_chat_client(self): # [START create_chat_client] - from azure.communication.chat import ChatClient, CommunicationTokenCredential - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) # [END create_chat_client] def create_thread(self): @@ -56,10 +57,12 @@ def create_thread(self): ChatClient, ChatThreadMember, CommunicationUserIdentifier, - CommunicationTokenCredential + CommunicationTokenCredential, + CommunicationTokenRefreshOptions ) - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) topic = "test topic" members = [ChatThreadMember( @@ -75,9 +78,10 @@ def create_thread(self): def get_chat_thread_client(self): # [START get_chat_thread_client] - from azure.communication.chat import ChatClient, CommunicationTokenCredential + from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) chat_thread_client = chat_client.get_chat_thread_client(self._thread_id) # [END get_chat_thread_client] @@ -85,9 +89,10 @@ def get_chat_thread_client(self): def get_thread(self): # [START get_thread] - from azure.communication.chat import ChatClient, CommunicationTokenCredential + from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) chat_thread = chat_client.get_chat_thread(self._thread_id) # [END get_thread] @@ -95,11 +100,12 @@ def get_thread(self): def list_threads(self): # [START list_threads] - from azure.communication.chat import ChatClient, CommunicationTokenCredential + from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions from datetime import datetime, timedelta import pytz - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) start_time = datetime.utcnow() - timedelta(days=2) start_time = start_time.replace(tzinfo=pytz.utc) chat_thread_infos = chat_client.list_chat_threads(results_per_page=5, start_time=start_time) @@ -111,9 +117,10 @@ def list_threads(self): def delete_thread(self): # [START delete_thread] - from azure.communication.chat import ChatClient, CommunicationTokenCredential + from azure.communication.chat import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) chat_client.delete_chat_thread(self._thread_id) # [END delete_thread] diff --git a/sdk/communication/azure-communication-chat/samples/chat_client_sample_async.py b/sdk/communication/azure-communication-chat/samples/chat_client_sample_async.py index fe1135ebfd40..7c22b5d8acb2 100644 --- a/sdk/communication/azure-communication-chat/samples/chat_client_sample_async.py +++ b/sdk/communication/azure-communication-chat/samples/chat_client_sample_async.py @@ -45,17 +45,20 @@ class ChatClientSamplesAsync(object): def create_chat_client(self): # [START create_chat_client] - from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) # [END create_chat_client] print("chat_client created") async def create_thread_async(self): from datetime import datetime - from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential + from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions from azure.communication.chat import ChatThreadMember, CommunicationUser - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) async with chat_client: # [START create_thread] topic = "test topic" @@ -72,18 +75,20 @@ async def create_thread_async(self): def get_chat_thread_client(self): # [START get_chat_thread_client] - from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential + from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) chat_thread_client = chat_client.get_chat_thread_client(self._thread_id) # [END get_chat_thread_client] print("chat_thread_client created with thread id: ", chat_thread_client.thread_id) async def get_thread_async(self): - from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential + from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) async with chat_client: # [START get_thread] chat_thread = await chat_client.get_chat_thread(self._thread_id) @@ -91,9 +96,10 @@ async def get_thread_async(self): print("get_thread succeeded, thread id: " + chat_thread.id + ", thread topic: " + chat_thread.topic) async def list_threads_async(self): - from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential + from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) async with chat_client: # [START list_threads] from datetime import datetime, timedelta @@ -107,9 +113,10 @@ async def list_threads_async(self): # [END list_threads] async def delete_thread_async(self): - from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential + from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) async with chat_client: # [START delete_thread] await chat_client.delete_chat_thread(self._thread_id) diff --git a/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample.py b/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample.py index b80a4ed63cde..c20ba6be0977 100644 --- a/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample.py +++ b/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample.py @@ -52,9 +52,11 @@ def create_chat_thread_client(self): ChatClient, ChatThreadMember, CommunicationUserIdentifier, - CommunicationTokenCredential + CommunicationTokenCredential, + CommunicationTokenRefreshOptions ) - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) topic = "test topic" members = [ChatThreadMember( user=self.user, @@ -68,8 +70,9 @@ def create_chat_thread_client(self): def update_thread(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START update_thread] topic = "updated thread topic" chat_thread_client.update_thread(topic=topic) @@ -79,8 +82,9 @@ def update_thread(self): def send_message(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START send_message] from azure.communication.chat import ChatMessagePriority @@ -99,8 +103,9 @@ def send_message(self): def get_message(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START get_message] chat_message = chat_thread_client.get_message(self._message_id) # [END get_message] @@ -110,8 +115,9 @@ def get_message(self): def list_messages(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START list_messages] from datetime import datetime, timedelta start_time = datetime.utcnow() - timedelta(days=1) @@ -125,8 +131,9 @@ def list_messages(self): def update_message(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START update_message] content = "updated content" chat_thread_client.update_message(self._message_id, content=content) @@ -136,8 +143,9 @@ def update_message(self): def send_read_receipt(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START send_read_receipt] chat_thread_client.send_read_receipt(self._message_id) # [END send_read_receipt] @@ -146,8 +154,9 @@ def send_read_receipt(self): def list_read_receipts(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START list_read_receipts] read_receipts = chat_thread_client.list_read_receipts() print("list_read_receipts succeeded, receipts:") @@ -157,8 +166,9 @@ def list_read_receipts(self): def delete_message(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START delete_message] chat_thread_client.delete_message(self._message_id) # [END delete_message] @@ -166,8 +176,9 @@ def delete_message(self): def list_members(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START list_members] chat_thread_members = chat_thread_client.list_members() print("list_chat_members succeeded, members: ") @@ -176,8 +187,9 @@ def list_members(self): # [END list_members] def add_members(self): - from azure.communication.chat import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START add_members] from azure.communication.chat import ChatThreadMember @@ -193,8 +205,9 @@ def add_members(self): def remove_member(self): from azure.communication.chat import ChatThreadClient - from azure.communication.chat import CommunicationTokenCredential, CommunicationUser - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import CommunicationTokenCredential, CommunicationUser, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START remove_member] chat_thread_client.remove_member(self.new_user) @@ -203,8 +216,9 @@ def remove_member(self): print("remove_chat_member succeeded") def send_typing_notification(self): - from azure.communication.chat import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) # [START send_typing_notification] chat_thread_client.send_typing_notification() # [END send_typing_notification] diff --git a/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample_async.py b/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample_async.py index 1dec7847314c..129c2c057e44 100644 --- a/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample_async.py +++ b/sdk/communication/azure-communication-chat/samples/chat_thread_client_sample_async.py @@ -49,10 +49,11 @@ class ChatThreadClientSamplesAsync(object): async def create_chat_thread_client_async(self): # [START create_chat_thread_client] from datetime import datetime - from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential + from azure.communication.chat.aio import ChatClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions from azure.communication.chat import ChatThreadMember, CommunicationUserIdentifier - chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) async with chat_client: topic = "test topic" @@ -68,8 +69,9 @@ async def create_chat_thread_client_async(self): print("thread created, id: " + self._thread_id) async def update_thread_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START update_thread] @@ -80,8 +82,9 @@ async def update_thread_async(self): print("update_thread succeeded") async def send_message_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START send_message] @@ -100,8 +103,9 @@ async def send_message_async(self): print("send_message succeeded, message id:", self._message_id) async def get_message_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START get_message] @@ -111,8 +115,9 @@ async def get_message_async(self): "content: ", chat_message.content) async def list_messages_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START list_messages] @@ -126,8 +131,9 @@ async def list_messages_async(self): # [END list_messages] async def update_message_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START update_message] @@ -137,8 +143,9 @@ async def update_message_async(self): print("update_message succeeded") async def send_read_receipt_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START send_read_receipt] @@ -148,8 +155,9 @@ async def send_read_receipt_async(self): print("send_read_receipt succeeded") async def list_read_receipts_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START list_read_receipts] @@ -160,8 +168,9 @@ async def list_read_receipts_async(self): print(read_receipt) async def delete_message_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START delete_message] @@ -170,8 +179,9 @@ async def delete_message_async(self): print("delete_message succeeded") async def list_members_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START list_members] @@ -182,8 +192,9 @@ async def list_members_async(self): # [END list_members] async def add_members_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START add_members] @@ -199,8 +210,9 @@ async def add_members_async(self): print("add_members succeeded") async def remove_member_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START remove_member] @@ -209,8 +221,9 @@ async def remove_member_async(self): print("remove_member_async succeeded") async def send_typing_notification_async(self): - from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential - chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(self.token), self._thread_id) + from azure.communication.chat.aio import ChatThreadClient, CommunicationTokenCredential, CommunicationTokenRefreshOptions + refresh_options = CommunicationTokenRefreshOptions(self.token) + chat_thread_client = ChatThreadClient(self.endpoint, CommunicationTokenCredential(refresh_options), self._thread_id) async with chat_thread_client: # [START send_typing_notification] diff --git a/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e.py b/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e.py index 57970249e001..f0b4a5189d80 100644 --- a/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e.py +++ b/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e.py @@ -14,6 +14,7 @@ from azure.communication.chat import ( ChatClient, CommunicationTokenCredential, + CommunicationTokenRefreshOptions, ChatThreadMember ) from azure.communication.chat._shared.utils import parse_connection_str @@ -48,7 +49,8 @@ def setUp(self): self.token = tokenresponse.token # create ChatClient - self.chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + self.chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) def tearDown(self): super(ChatClientTest, self).tearDown() diff --git a/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e_async.py b/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e_async.py index 1fdc7590a2ed..a3fe1a3750d4 100644 --- a/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e_async.py +++ b/sdk/communication/azure-communication-chat/tests/test_chat_client_e2e_async.py @@ -12,7 +12,8 @@ from azure.communication.administration import CommunicationIdentityClient from azure.communication.chat.aio import ( ChatClient, - CommunicationTokenCredential + CommunicationTokenCredential, + CommunicationTokenRefreshOptions ) from azure.communication.chat import ( ChatThreadMember @@ -46,7 +47,8 @@ def setUp(self): self.token = token_response.token # create ChatClient - self.chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + self.chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) def tearDown(self): super(ChatClientTestAsync, self).tearDown() diff --git a/sdk/communication/azure-communication-chat/tests/test_chat_thread_client_e2e.py b/sdk/communication/azure-communication-chat/tests/test_chat_thread_client_e2e.py index 87a1a797da29..9a90b1a79662 100644 --- a/sdk/communication/azure-communication-chat/tests/test_chat_thread_client_e2e.py +++ b/sdk/communication/azure-communication-chat/tests/test_chat_thread_client_e2e.py @@ -14,6 +14,7 @@ from azure.communication.chat import ( ChatClient, CommunicationTokenCredential, + CommunicationTokenRefreshOptions, ChatThreadMember, ChatMessagePriority ) @@ -51,7 +52,8 @@ def setUp(self): self.new_user = self.identity_client.create_user() # create ChatClient - self.chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(self.token)) + refresh_options = CommunicationTokenRefreshOptions(self.token) + self.chat_client = ChatClient(self.endpoint, CommunicationTokenCredential(refresh_options)) def tearDown(self): super(ChatThreadClientTest, self).tearDown() diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential.py index 73b494b8ccf3..e920d356a518 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential.py @@ -9,27 +9,22 @@ cast, Tuple, ) -import six + from msrest.serialization import TZ_UTC -from .utils import create_access_token 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 - :raises: TypeError + :param communication_token_refresh_options: The token used to authenticate to an Azure Communication service + :type communication_token_refresh_options: ~azure.communication.chat.CommunicationTokenRefreshOptions """ ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - token_refresher=None + communication_token_refresh_options ): - # type: (str) -> None - if not isinstance(token, six.string_types): - raise TypeError("token must be a string.") - self._token = create_access_token(token) - self._token_refresher = token_refresher + self._token = communication_token_refresh_options.get_token() + self._token_refresher = communication_token_refresh_options.get_token_refresher() self._lock = Condition(Lock()) self._some_thread_refreshing = False @@ -70,7 +65,6 @@ def get_token(self): self._lock.notify_all() raise - return self._token def _wait_till_inprogress_thread_finish_refreshing(self): diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential_async.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential_async.py index 710c9948c839..0918074eb04a 100644 --- a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential_async.py +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_credential_async.py @@ -9,27 +9,23 @@ cast, Tuple, ) -import six + from msrest.serialization import TZ_UTC -from .utils import create_access_token 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 + :param communication_token_refresh_options: The token used to authenticate to an Azure Communication service + :type communication_token_refresh_options: ~azure.communication.chat.aio.CommunicationTokenRefreshOptions :raises: TypeError """ ON_DEMAND_REFRESHING_INTERVAL_MINUTES = 2 def __init__(self, - token, # type: str - token_refresher=None + communication_token_refresh_options ): - # type: (str) -> None - if not isinstance(token, six.string_types): - raise TypeError("token must be a string.") - self._token = create_access_token(token) - self._token_refresher = token_refresher + self._token = communication_token_refresh_options.get_token() + self._token_refresher = communication_token_refresh_options.get_token_refresher() self._lock = Condition(Lock()) self._some_thread_refreshing = False diff --git a/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_token_refresh_options.py b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_token_refresh_options.py new file mode 100644 index 000000000000..6bdc0d456026 --- /dev/null +++ b/sdk/communication/azure-communication-sms/azure/communication/sms/_shared/user_token_refresh_options.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +from typing import ( # pylint: disable=unused-import + cast, + Tuple, +) +import six +from .utils import create_access_token + +class CommunicationTokenRefreshOptions(object): + """Options for refreshing CommunicationTokenCredential. + :param str token: The token used to authenticate to an Azure Communication service + :param token_refresher: The token refresher to provide capacity to fetch fresh token + :raises: TypeError + """ + + def __init__(self, + token, # type: str + token_refresher=None + ): + # type: (str) -> None + if not isinstance(token, six.string_types): + raise TypeError("token must be a string.") + self._token = token + self._token_refresher = token_refresher + + def get_token(self): + """Return the the serialized JWT token.""" + return create_access_token(self._token) + + def get_token_refresher(self): + """Return the token refresher to provide capacity to fetch fresh token.""" + return self._token_refresher