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] - SMS - Added AAD support #16076

Merged
merged 2 commits into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sdk/communication/azure-communication-sms/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Release History

## 1.0.0b5 (Unreleased)
### Added

- Added support for Azure Active Directory authentication

## 1.0.0b4 (2020-11-16)
- Updated `azure-communication-sms` version.
Expand Down
11 changes: 9 additions & 2 deletions sdk/communication/azure-communication-sms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ The following section provides several code snippets covering some of the most c

### Client Initialization

To initialize the SMS Client, the connection string can be used to instantiate:
To initialize the SMS Client, the connection string can be used to instantiate.
Alternatively, you can also use Active Directory authentication using DefaultAzureCredential.

```Python
connection_string = "COMMUNICATION_SERVICES_CONNECTION_STRING"
from azure.identity import DefaultAzureCredential

connection_str = os.getenv('AZURE_COMMUNICATION_SERVICE_CONNECTION_STRING')
sms_client = SmsClient.from_connection_string(connection_string)
# To use Azure Active Directory Authentication (DefaultAzureCredential) make sure to have
# AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET as env variables.
endpoint = os.getenv('AZURE_COMMUNICATION_SERVICE_ENDPOINT')
sms_client = SmsClient(endpoint, DefaultAzureCredential())
```

### Sending an SMS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,36 @@ def create_access_token(token):
return AccessToken(token, datetime.fromtimestamp(payload['exp']).replace(tzinfo=TZ_UTC))
except ValueError:
raise ValueError(token_parse_err_msg)

def get_authentication_policy(
endpoint, # type: str
credential, # type: TokenCredential or str
is_async=False, # type: bool
):
# type: (...) -> BearerTokenCredentialPolicy or HMACCredentialPolicy
"""Returns the correct authentication policy based
on which credential is being passed.

:param endpoint: The endpoint to which we are authenticating to.
:type endpoint: str
:param credential: The credential we use to authenticate to the service
:type credential: TokenCredential or str
:param isAsync: For async clients there is a need to decode the url
:type bool: isAsync or str

:rtype: ~azure.core.pipeline.policies.BearerTokenCredentialPolicy
~HMACCredentialsPolicy
"""

if credential is None:
raise ValueError("Parameter 'credential' must not be None.")
if hasattr(credential, "get_token"):
from azure.core.pipeline.policies import BearerTokenCredentialPolicy
return BearerTokenCredentialPolicy(
credential, "https://communication.azure.com//.default")
if isinstance(credential, str):
from .._shared.policy import HMACCredentialsPolicy
return HMACCredentialsPolicy(endpoint, credential, decode_url=is_async)

raise TypeError("Unsupported credential: {}. Use an access token string to use HMACCredentialsPolicy"
"or a token credential from azure.identity".format(type(credential)))
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
from azure.communication.sms._generated.models import SendSmsResponse

from ._generated._azure_communication_sms_service import AzureCommunicationSMSService
from ._shared.policy import HMACCredentialsPolicy
from ._shared.utils import parse_connection_str
from ._shared.utils import parse_connection_str, get_authentication_policy
from ._version import SDK_MONIKER

class SmsClient(object):
Expand Down Expand Up @@ -41,8 +40,7 @@ def __init__(
"invalid credential from connection string.")

self._endpoint = endpoint
self._authentication_policy = HMACCredentialsPolicy(endpoint, credential)

self._authentication_policy = get_authentication_policy(endpoint, credential)
self._sms_service_client = AzureCommunicationSMSService(
self._endpoint,
authentication_policy=self._authentication_policy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
from azure.communication.sms._generated.models import SendSmsResponse

from .._generated.aio._azure_communication_sms_service import AzureCommunicationSMSService
from .._shared.policy import HMACCredentialsPolicy
from .._shared.utils import parse_connection_str
from .._shared.utils import parse_connection_str, get_authentication_policy
from .._version import SDK_MONIKER

class SmsClient(object):
Expand Down Expand Up @@ -41,7 +40,7 @@ def __init__(
"invalid credential from connection string.")

self._endpoint = endpoint
self._authentication_policy = HMACCredentialsPolicy(endpoint, credential)
self._authentication_policy = get_authentication_policy(endpoint, credential)

self._sms_service_client = AzureCommunicationSMSService(
self._endpoint,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
-e ../../../tools/azure-sdk-tools
-e ../../../tools/azure-devtools
-e ../../identity/azure-identity
../../core/azure-core
../azure-communication-nspkg
aiohttp>=3.0; python_version >= '3.5'
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 09 Oct 2020 23:20:19 GMT
- Wed, 20 Jan 2021 18:11:23 GMT
User-Agent:
- azsdk-python-communication-sms/1.0.0b3 Python/3.8.6 (Windows-10-10.0.19041-SP0)
- azsdk-python-communication-sms/1.0.0b5 Python/3.8.5 (Windows-10-10.0.19041-SP0)
x-ms-return-client-request-id:
- 'true'
method: POST
Expand All @@ -27,13 +27,15 @@ interactions:
content-type:
- application/json; charset=utf-8
date:
- Fri, 09 Oct 2020 23:20:19 GMT
- Wed, 20 Jan 2021 18:11:24 GMT
ms-cv:
- JCf4xQXQEkS2Tix1X3WyhA.0
- 1y4+o6OmR0ulV50uPXHoEw.0
request-context:
- appId=
transfer-encoding:
- chunked
x-processing-time:
- 1071ms
- 484ms
status:
code: 200
message: OK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ interactions:
Content-Type:
- application/json
Date:
- Fri, 09 Oct 2020 23:20:20 GMT
- Wed, 20 Jan 2021 18:11:24 GMT
User-Agent:
- azsdk-python-communication-sms/1.0.0b3 Python/3.8.6 (Windows-10-10.0.19041-SP0)
- azsdk-python-communication-sms/1.0.0b5 Python/3.8.5 (Windows-10-10.0.19041-SP0)
x-ms-return-client-request-id:
- 'true'
method: POST
Expand All @@ -21,10 +21,11 @@ interactions:
body: '{"messageId": "sanitized"}'
headers:
content-type: application/json; charset=utf-8
date: Fri, 09 Oct 2020 23:20:20 GMT
ms-cv: Fh5qIzKnFUaqzbz+3C3fKQ.0
date: Wed, 20 Jan 2021 18:11:24 GMT
ms-cv: x7uY4q7a+EmmyTMUW8my+A.0
request-context: appId=
transfer-encoding: chunked
x-processing-time: 815ms
x-processing-time: 468ms
status:
code: 200
message: OK
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
interactions:
- request:
body: '{"from": "sanitized", "to": "sanitized", "message": "Hello World via SMS",
"sendSmsOptions": {"enableDeliveryReport": true}}'
headers:
Accept:
- application/json
Content-Length:
- '132'
Content-Type:
- application/json
User-Agent:
- azsdk-python-communication-sms/1.0.0b5 Python/3.8.5 (Windows-10-10.0.19041-SP0)
method: POST
uri: https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1
response:
body: '{"messageId": "sanitized"}'
headers:
content-type: application/json; charset=utf-8
date: Wed, 20 Jan 2021 18:11:27 GMT
ms-cv: 2alAVqPXy0O98kSmG+jzFA.0
request-context: appId=
transfer-encoding: chunked
x-processing-time: 827ms
status:
code: 200
message: OK
url: https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1
version: 1
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@

import os
import pytest
from azure.core.credentials import AccessToken
from azure.communication.sms.aio import SmsClient
from azure.communication.sms import (
PhoneNumber, SendSmsOptions
)
from azure.communication.sms._shared.utils import parse_connection_str
from _shared.asynctestcase import AsyncCommunicationTestCase
from _shared.testcase import (
BodyReplacerProcessor, ResponseReplacerProcessor
)
from azure.identity import DefaultAzureCredential


class FakeTokenCredential(object):
def __init__(self):
self.token = AccessToken("Fake Token", 0)

def get_token(self, *args):
return self.token
class SMSClientTestAsync(AsyncCommunicationTestCase):
def __init__(self, method_name):
super(SMSClientTestAsync, self).__init__(method_name)
Expand Down Expand Up @@ -46,3 +56,24 @@ async def test_send_sms_async(self):
send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property

assert sms_response.message_id is not None

@AsyncCommunicationTestCase.await_prepared_test
@pytest.mark.live_test_only
async def test_send_sms_async_from_managed_identity(self):
endpoint, access_key = parse_connection_str(self.connection_str)
from devtools_testutils import is_live
if not is_live():
credential = FakeTokenCredential()
else:
credential = DefaultAzureCredential()
sms_client = SmsClient(endpoint, credential)
print(sms_client)
async with sms_client:
# calling send() with sms values
sms_response = await sms_client.send(
from_phone_number=PhoneNumber(self.phone_number),
to_phone_numbers=[PhoneNumber(self.phone_number)],
message="Hello World via SMS",
send_sms_options=SendSmsOptions(enable_delivery_report=True)) # optional property

assert sms_response.message_id is not None