Skip to content

Commit

Permalink
[Communication] - Authentication - SmsClient auth using token credent…
Browse files Browse the repository at this point in the history
…ial (Azure#13260)

* [smsClient] introduce new constructor
* [smsClientWithToken] flesh out the unit test for sms client
* [smsClientWithToken.spec.ts] adding new replacable variables for token auth
* [smsClientWithToken.spec] Adding new sms recordings and skipping tests if credentials cannot be created. Mainly for browser mode
* [recording] adding browser recordings
* [recordedClient] introducing new utils for sms test
  • Loading branch information
JoshuaLai authored and ljian3377 committed Jan 22, 2021
1 parent 0bd081f commit 645a11d
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 11 deletions.
3 changes: 3 additions & 0 deletions sdk/communication/communication-sms/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## 1.0.0-beta.4 (Unreleased)

### Added

- `SmsClient` added a constructor that supports `TokenCredential`.

## 1.0.0-beta.3 (2020-11-16)

Expand Down
10 changes: 10 additions & 0 deletions sdk/communication/communication-sms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ const connectionString = `endpoint=<Host>;accessKey=<Base64-Encoded-Key>`;
const client = new SmsClient(connectionString);
```

### Using a `TokenCredential`

```typescript
import { DefaultAzureCredential } from "@azure/identity";
import { CommunicationIdentityClient } from "@azure/communication-administration";

const credential = new DefaultAzureCredential();
const client = new CommunicationIdentityClient("<Host>", credential);
```

## Sending SMS

```typescript
Expand Down
6 changes: 5 additions & 1 deletion sdk/communication/communication-sms/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ module.exports = function(config) {
envPreprocessor: [
"AZURE_COMMUNICATION_LIVETEST_CONNECTION_STRING",
"AZURE_PHONE_NUMBER",
"TEST_MODE"
"TEST_MODE",
"COMMUNICATION_ENDPOINT",
"AZURE_CLIENT_ID",
"AZURE_CLIENT_SECRET",
"AZURE_TENANT_ID"
],

// test results reporter to use
Expand Down
1 change: 1 addition & 0 deletions sdk/communication/communication-sms/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
"devDependencies": {
"@azure/dev-tool": "^1.0.0",
"@azure/eslint-plugin-azure-sdk": "^3.0.0",
"@azure/identity": "^1.1.0",
"@azure/test-utils-recorder": "^1.0.0",
"@microsoft/api-extractor": "7.7.11",
"@rollup/plugin-commonjs": "11.0.2",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { KeyCredential } from '@azure/core-auth';
import { OperationOptions } from '@azure/core-http';
import { PipelineOptions } from '@azure/core-http';
import { RestResponse } from '@azure/core-http';
import { TokenCredential } from '@azure/core-auth';

// @public
export interface SendOptions extends OperationOptions {
Expand All @@ -25,6 +26,7 @@ export interface SendRequest {
export class SmsClient {
constructor(connectionString: string, options?: SmsClientOptions);
constructor(url: string, credential: KeyCredential, options?: SmsClientOptions);
constructor(url: string, credential: TokenCredential, options?: SmsClientOptions);
send(sendRequest: SendRequest, options?: SendOptions): Promise<RestResponse>;
}

Expand Down
18 changes: 13 additions & 5 deletions sdk/communication/communication-sms/src/smsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// Licensed under the MIT license.

import {
createCommunicationAccessKeyCredentialPolicy,
parseClientArguments,
isKeyCredential
isKeyCredential,
createCommunicationAuthPolicy
} from "@azure/communication-common";
import { KeyCredential } from "@azure/core-auth";
import { KeyCredential, TokenCredential } from "@azure/core-auth";
import {
RestResponse,
PipelineOptions,
Expand Down Expand Up @@ -87,9 +87,17 @@ export class SmsClient {
*/
constructor(url: string, credential: KeyCredential, options?: SmsClientOptions);

/**
* Initializes a new instance of the SmsClient class using a TokenCredential.
* @param url The endpoint of the service (ex: https://contoso.eastus.communications.azure.net).
* @param credential TokenCredential that is used to authenticate requests to the service.
* @param options Optional. Options to configure the HTTP pipeline.
*/
constructor(url: string, credential: TokenCredential, options?: SmsClientOptions);

constructor(
connectionStringOrUrl: string,
credentialOrOptions?: KeyCredential | SmsClientOptions,
credentialOrOptions?: KeyCredential | TokenCredential | SmsClientOptions,
maybeOptions: SmsClientOptions = {}
) {
const { url, credential } = parseClientArguments(connectionStringOrUrl, credentialOrOptions);
Expand All @@ -115,7 +123,7 @@ export class SmsClient {
}
};

const authPolicy = createCommunicationAccessKeyCredentialPolicy(credential as KeyCredential);
const authPolicy = createCommunicationAuthPolicy(credential);
const pipeline = createPipelineFromOptions(internalPipelineOptions, authPolicy);

this.api = new SmsApiClient(url, pipeline);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { record, Recorder, env } from "@azure/test-utils-recorder";
import { SendRequest, SmsClient } from "../src/smsClient";
import { assert } from "chai";
import { isNode } from "@azure/core-http";
import * as dotenv from "dotenv";
import { createCredential, recorderConfiguration } from "./utils/recordedClient";

if (isNode) {
dotenv.config();
}

describe("SmsClientWithToken [Playback/Live]", async () => {
let recorder: Recorder;

beforeEach(async function() {
recorder = record(this, recorderConfiguration);
});

afterEach(async function() {
if (!this.currentTest?.isPending()) {
await recorder.stop();
}
});

it("successfully issues a token for a user", async function() {
const credential = createCredential();

if (!credential) {
this.skip();
}

const endpoint = env.COMMUNICATION_ENDPOINT;
const fromNumber = env.AZURE_PHONE_NUMBER;
const toNumber = env.AZURE_PHONE_NUMBER;

const smsClient = new SmsClient(endpoint, credential);
const sendRequest: SendRequest = {
from: fromNumber,
to: [toNumber],
message: "test message"
};

const response = await smsClient.send(sendRequest);
assert.equal(response._response.status, 200);
}).timeout(5000);
});
35 changes: 35 additions & 0 deletions sdk/communication/communication-sms/test/utils/recordedClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { DefaultAzureCredential, TokenCredential } from "@azure/identity";
import { isPlaybackMode, RecorderEnvironmentSetup } from "@azure/test-utils-recorder";

export const recorderConfiguration: RecorderEnvironmentSetup = {
replaceableVariables: {
AZURE_COMMUNICATION_LIVETEST_CONNECTION_STRING: "endpoint=https://endpoint/;accesskey=banana",
AZURE_PHONE_NUMBER: "+18005551234",
COMMUNICATION_ENDPOINT: "https://endpoint/",
AZURE_CLIENT_ID: "SomeClientId",
AZURE_CLIENT_SECRET: "SomeClientSecret",
AZURE_TENANT_ID: "SomeTenantId"
},
customizationsOnRecordings: [
(recording: string): string => recording.replace(/(https:\/\/)([^\/',]*)/, "$1endpoint"),
(recording: string): string =>
recording.replace(/"messageId"\s?:\s?"[^"]*"/g, `"messageId":"Sanitized"`)
],
queryParametersToSkip: []
};

export function createCredential(): TokenCredential | undefined {
if (isPlaybackMode()) {
return {
getToken: async (_scopes) => {
return { token: "testToken", expiresOnTimestamp: 11111 };
}
};
} else {
try {
return new DefaultAzureCredential();
} catch {
return undefined;
}
}
}

0 comments on commit 645a11d

Please sign in to comment.