Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Communication] Use CommunicationRefreshOptions in CommunicaitonTokenCredential #16228

Merged
merged 11 commits into from
Jan 20, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -70,7 +65,6 @@ def get_token(self):
self._lock.notify_all()

raise

return self._token

def _wait_till_inprogress_thread_finish_refreshing(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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, # type: str
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: type comment seems to be misplaced?

token,
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
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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()
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ChatThreadInfo,
)
from ._shared.user_credential import CommunicationTokenCredential
from ._shared.user_token_refresh_options import CommunicationTokenRefreshOptions
from ._models import (
ChatThreadMember,
ChatMessage,
Expand All @@ -25,6 +26,7 @@
'ChatThread',
'ChatThreadInfo',
'CommunicationTokenCredential',
'CommunicationTokenRefreshOptions',
'ChatThreadMember',
'CommunicationUserIdentifier',
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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, # type: str
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: here too, the type comment should be below

token,
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
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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(
Expand All @@ -75,31 +78,34 @@ 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]

print("chat_thread_client created with thread id: ", chat_thread_client.thread_id)

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]

print("get_thread succeeded, thread id: " + chat_thread.id + ", thread topic: " + chat_thread.topic)

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)
Expand All @@ -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]

Expand Down
Loading