From 103028a935acb86b54f812a0296152838e5d15bb Mon Sep 17 00:00:00 2001 From: minnieliu Date: Fri, 22 Jan 2021 16:33:07 -0800 Subject: [PATCH] [Communication] - SMS - Managed Identity Support for SMS Client (#17867) * Managed Identity for SMS * Adding readme env variables detail * Fix changelog * Adding live tests for managed identity SMS * Resolve merge conflicts * Remove extra connection string variable * Remove endpoint and parse from connection string * Updating tsts Co-authored-by: Minnie Liu --- .../Azure.Communication.Sms/CHANGELOG.md | 1 + .../Azure.Communication.Sms/README.md | 9 ++++ .../Azure.Communication.Sms.netstandard2.0.cs | 1 + .../Azure.Communication.Sms/src/SmsClient.cs | 23 +++++++++++ ...ndingAnSmsMessageUsingTokenCredential.json | 41 +++++++++++++++++++ ...AnSmsMessageUsingTokenCredentialAsync.json | 41 +++++++++++++++++++ .../tests/SmsClientLiveTests.cs | 39 ++++++++++++++++++ .../tests/SmsClientTestEnvironment.cs | 1 + .../tests/samples/Sample1_SmsClient.cs | 13 ++++++ 9 files changed, 169 insertions(+) create mode 100644 sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredential.json create mode 100644 sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredentialAsync.json diff --git a/sdk/communication/Azure.Communication.Sms/CHANGELOG.md b/sdk/communication/Azure.Communication.Sms/CHANGELOG.md index 776ad0cd9bd49..2a70a6445b8ac 100644 --- a/sdk/communication/Azure.Communication.Sms/CHANGELOG.md +++ b/sdk/communication/Azure.Communication.Sms/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added - Added support to create SmsClient with AzureKeyCredential. +- Support for creating SmsClient with TokenCredential ## 1.0.0-beta.3 (2020-11-16) diff --git a/sdk/communication/Azure.Communication.Sms/README.md b/sdk/communication/Azure.Communication.Sms/README.md index 5006f6f60b20f..1dfef37bd555c 100644 --- a/sdk/communication/Azure.Communication.Sms/README.md +++ b/sdk/communication/Azure.Communication.Sms/README.md @@ -36,6 +36,15 @@ string connectionString = "YOUR_CONNECTION_STRING"; // Find your Communication S SmsClient client = new SmsClient(connectionString); ``` +Alternatively, SMS clients can also be authenticated using a valid token credential. With this option, +`AZURE_CLIENT_SECRET`, `AZURE_CLIENT_ID` and `AZURE_TENANT_ID` environment variables need to be set up for authentication. + +```C# Snippet:Azure_Communication_Sms_Tests_Samples_CreateSmsClientWithToken +string endpoint = ""; +TokenCredential tokenCredential = new DefaultAzureCredential(); +SmsClient client = new SmsClient(new Uri(endpoint), tokenCredential); +``` + ## Examples ### Send a SMS Message To send a SMS message, call the `Send` or `SendAsync` function from the `SmsClient`. diff --git a/sdk/communication/Azure.Communication.Sms/api/Azure.Communication.Sms.netstandard2.0.cs b/sdk/communication/Azure.Communication.Sms/api/Azure.Communication.Sms.netstandard2.0.cs index b4148c5547004..caa9ec7378ed9 100644 --- a/sdk/communication/Azure.Communication.Sms/api/Azure.Communication.Sms.netstandard2.0.cs +++ b/sdk/communication/Azure.Communication.Sms/api/Azure.Communication.Sms.netstandard2.0.cs @@ -15,6 +15,7 @@ public partial class SmsClient protected SmsClient() { } public SmsClient(string connectionString, Azure.Communication.Sms.SmsClientOptions? options = null) { } public SmsClient(System.Uri endpoint, Azure.AzureKeyCredential keyCredential, Azure.Communication.Sms.SmsClientOptions? options = null) { } + public SmsClient(System.Uri endpoint, Azure.Core.TokenCredential tokenCredential, Azure.Communication.Sms.SmsClientOptions? options = null) { } public virtual Azure.Response Send(Azure.Communication.PhoneNumberIdentifier from, Azure.Communication.PhoneNumberIdentifier to, string message, Azure.Communication.Sms.SendSmsOptions? sendSmsOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response Send(Azure.Communication.PhoneNumberIdentifier from, System.Collections.Generic.IEnumerable to, string message, Azure.Communication.Sms.SendSmsOptions? sendSmsOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> SendAsync(Azure.Communication.PhoneNumberIdentifier from, Azure.Communication.PhoneNumberIdentifier to, string message, Azure.Communication.Sms.SendSmsOptions? sendSmsOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } diff --git a/sdk/communication/Azure.Communication.Sms/src/SmsClient.cs b/sdk/communication/Azure.Communication.Sms/src/SmsClient.cs index f631b2cac5e1a..8180952ed5b19 100644 --- a/sdk/communication/Azure.Communication.Sms/src/SmsClient.cs +++ b/sdk/communication/Azure.Communication.Sms/src/SmsClient.cs @@ -40,6 +40,17 @@ public SmsClient(string connectionString, SmsClientOptions? options = default) ConnectionString.Parse(AssertNotNullOrEmpty(connectionString, nameof(connectionString)))) { } + /// Initializes a new instance of . + /// The URI of the Azure Communication Services resource. + /// The TokenCredential used to authenticate requests, such as DefaultAzureCredential. + /// Client option exposing , , , etc. + public SmsClient(Uri endpoint, TokenCredential tokenCredential, SmsClientOptions? options = default) + : this( + endpoint, + options ?? new SmsClientOptions(), + tokenCredential) + { } + /// Initializes a new instance of for mocking. protected SmsClient() { @@ -60,6 +71,18 @@ private SmsClient(SmsClientOptions options, ConnectionString connectionString) endpointUrl: connectionString.GetRequired("endpoint")) { } + private SmsClient(Uri endpoint, SmsClientOptions options, TokenCredential tokenCredential) + { + Argument.AssertNotNull(endpoint, nameof(endpoint)); + Argument.AssertNotNull(tokenCredential, nameof(tokenCredential)); + + _clientDiagnostics = new ClientDiagnostics(options); + RestClient = new SmsRestClient( + _clientDiagnostics, + options.BuildHttpPipeline(tokenCredential), + endpoint.AbsoluteUri); + } + private SmsClient(Uri endpoint, SmsClientOptions options, AzureKeyCredential credential) { _clientDiagnostics = new ClientDiagnostics(options); diff --git a/sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredential.json b/sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredential.json new file mode 100644 index 0000000000000..1bb1f162ab513 --- /dev/null +++ b/sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredential.json @@ -0,0 +1,41 @@ +{ + "Entries": [ + { + "RequestUri": "https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1", + "RequestMethod": "POST", + "RequestHeaders": { + "Accept": "application/json", + "Authorization": "Sanitized", + "Content-Length": "52", + "Content-Type": "application/json", + "traceparent": "00-4ebfbbc73311f445953967885e026c77-d82733a4d8f4294e-00", + "User-Agent": "azsdk-net-Communication.Sms/1.0.0-alpha.20210122.1 (.NET Framework 4.8.4250.0; Microsoft Windows 10.0.19042 )", + "x-ms-client-request-id": "ddd2d685f5a71640030c44e583eda6af", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "from": "Sanitized", + "to": "Sanitized", + "message": "Hi" + }, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 22 Jan 2021 22:27:45 GMT", + "MS-CV": "kdQ6MVzw50ytlWGIEfUh2A.0", + "Request-Context": "appId=", + "Transfer-Encoding": "chunked", + "X-Azure-Ref": "0YFELYAAAAAC0rVqpijwtSZebppOhJLzzRVdSMzBFREdFMDUxOQA5ZmM3YjUxOS1hOGNjLTRmODktOTM1ZS1jOTE0OGFlMDllODE=", + "X-Processing-Time": "610ms" + }, + "ResponseBody": { + "messageId": "Sanitized" + } + } + ], + "Variables": { + "AZURE_PHONE_NUMBER": "\u002B18005555555", + "COMMUNICATION_CONNECTION_STRING": "endpoint=https://sanitized.communication.azure.com/;accesskey=Kg==", + "RandomSeed": "2133348696" + } +} \ No newline at end of file diff --git a/sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredentialAsync.json b/sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredentialAsync.json new file mode 100644 index 0000000000000..2d2e7b24d33a4 --- /dev/null +++ b/sdk/communication/Azure.Communication.Sms/tests/SessionRecords/SmsClientLiveTests/SendingAnSmsMessageUsingTokenCredentialAsync.json @@ -0,0 +1,41 @@ +{ + "Entries": [ + { + "RequestUri": "https://sanitized.communication.azure.com/sms?api-version=2020-07-20-preview1", + "RequestMethod": "POST", + "RequestHeaders": { + "Accept": "application/json", + "Authorization": "Sanitized", + "Content-Length": "52", + "Content-Type": "application/json", + "traceparent": "00-5cab811796282d449f071b84f14c9bf7-3efdb19660afe84a-00", + "User-Agent": "azsdk-net-Communication.Sms/1.0.0-alpha.20210122.1 (.NET Framework 4.8.4250.0; Microsoft Windows 10.0.19042 )", + "x-ms-client-request-id": "70b55de3f1257ab8bb2712ab2776f6a2", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "from": "Sanitized", + "to": "Sanitized", + "message": "Hi" + }, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 22 Jan 2021 22:27:46 GMT", + "MS-CV": "5MLoBg5J3kGBm8DARZPmGw.0", + "Request-Context": "appId=", + "Transfer-Encoding": "chunked", + "X-Azure-Ref": "0YlELYAAAAAATVaXXVcnTRLyg8\u002BGVdlUnRVdSMzBFREdFMDUxOQA5ZmM3YjUxOS1hOGNjLTRmODktOTM1ZS1jOTE0OGFlMDllODE=", + "X-Processing-Time": "419ms" + }, + "ResponseBody": { + "messageId": "Sanitized" + } + } + ], + "Variables": { + "AZURE_PHONE_NUMBER": "\u002B18005555555", + "COMMUNICATION_CONNECTION_STRING": "endpoint=https://sanitized.communication.azure.com/;accesskey=Kg==", + "RandomSeed": "452036772" + } +} \ No newline at end of file diff --git a/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTests.cs b/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTests.cs index bb933024a57e8..9bb2ceca898b0 100644 --- a/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTests.cs +++ b/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTests.cs @@ -6,7 +6,9 @@ //@@ using Azure.Communication.Sms; #endregion Snippet:Azure_Communication_Sms_Tests_UsingStatements using System.Threading.Tasks; +using Azure.Core; using Azure.Core.TestFramework; +using Azure.Identity; using NUnit.Framework; namespace Azure.Communication.Sms.Tests @@ -48,5 +50,42 @@ public async Task SendingAnSmsMessage() Assert.Fail($"Unexpected error: {ex}"); } } + + [Test] + public async Task SendingAnSmsMessageUsingTokenCredential() + { + TokenCredential tokenCredential; + if (Mode == RecordedTestMode.Playback) + { + tokenCredential = new MockCredential(); + } + else + { + tokenCredential = new DefaultAzureCredential(); + } + SmsClient client = InstrumentClient( + new SmsClient( + new Uri(ConnectionString.Parse(TestEnvironment.ConnectionString, allowEmptyValues: true).GetRequired("endpoint")), + tokenCredential, + InstrumentClientOptions(new SmsClientOptions()))); + + try + { + SendSmsResponse result = await client.SendAsync( + from: new PhoneNumberIdentifier(TestEnvironment.PhoneNumber), + to: new PhoneNumberIdentifier(TestEnvironment.PhoneNumber), + message: "Hi"); + Console.WriteLine($"Sms id: {result.MessageId}"); + Assert.IsFalse(string.IsNullOrWhiteSpace(result.MessageId)); + } + catch (RequestFailedException ex) + { + Console.WriteLine(ex.Message); + } + catch (Exception ex) + { + Assert.Fail($"Unexpected error: {ex}"); + } + } } } diff --git a/sdk/communication/Azure.Communication.Sms/tests/SmsClientTestEnvironment.cs b/sdk/communication/Azure.Communication.Sms/tests/SmsClientTestEnvironment.cs index bd3c25973be31..b0097bc547234 100644 --- a/sdk/communication/Azure.Communication.Sms/tests/SmsClientTestEnvironment.cs +++ b/sdk/communication/Azure.Communication.Sms/tests/SmsClientTestEnvironment.cs @@ -11,6 +11,7 @@ public class SmsClientTestEnvironment : TestEnvironment public string ConnectionString => GetRecordedVariable(CommunicationRecordedTestSanitizer.ConnectionStringEnvironmentVariableName); internal const string PhoneNumberEnvironmentVariableName = "AZURE_PHONE_NUMBER"; + public string PhoneNumber => GetRecordedVariable(PhoneNumberEnvironmentVariableName); } } diff --git a/sdk/communication/Azure.Communication.Sms/tests/samples/Sample1_SmsClient.cs b/sdk/communication/Azure.Communication.Sms/tests/samples/Sample1_SmsClient.cs index d8bb37d29230e..1adb81f100b80 100644 --- a/sdk/communication/Azure.Communication.Sms/tests/samples/Sample1_SmsClient.cs +++ b/sdk/communication/Azure.Communication.Sms/tests/samples/Sample1_SmsClient.cs @@ -1,6 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using Azure.Core; +using Azure.Identity; + namespace Azure.Communication.Sms.Tests.samples { /// @@ -16,5 +20,14 @@ public SmsClient CreateSmsClient() #endregion Snippet:Azure_Communication_Sms_Tests_Samples_CreateSmsClient return client; } + public SmsClient CreateSmsClientWithToken() + { + #region Snippet:Azure_Communication_Sms_Tests_Samples_CreateSmsClientWithToken + string endpoint = ""; + TokenCredential tokenCredential = new DefaultAzureCredential(); + SmsClient client = new SmsClient(new Uri(endpoint), tokenCredential); + #endregion Snippet:Azure_Communication_Sms_Tests_Samples_CreateSmsClientWithToken + return client; + } } }