Skip to content

Commit

Permalink
fix: [#4408] Cloud adapter is not working with teams SSO (#4427)
Browse files Browse the repository at this point in the history
* Updated teamsSSOTokenExchangeMiddleware.ts

* Updated wrong provided token message

* Code improvements

* Suggested changes applied

* Added unit tests.

---------

Co-authored-by: Emiliano Quiroga <emiliano.quiroga@7-11.com>
  • Loading branch information
erquirogasw and Emiliano Quiroga committed Feb 8, 2023
1 parent 6e11d14 commit fbd66a2
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 8 deletions.
29 changes: 21 additions & 8 deletions libraries/botbuilder/src/teams/teamsSSOTokenExchangeMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import {
TokenResponse,
TurnContext,
tokenExchangeOperationName,
CloudAdapterBase,
} from 'botbuilder-core';
import { UserTokenClient } from 'botframework-connector';

function getStorageKey(context: TurnContext): string {
const activity = context.activity;
Expand Down Expand Up @@ -138,16 +140,27 @@ export class TeamsSSOTokenExchangeMiddleware implements Middleware {
let tokenExchangeResponse: TokenResponse;
const tokenExchangeRequest: TokenExchangeInvokeRequest = context.activity.value;

const tokenProvider = ExchangeToken.parse(context.adapter);

// TODO(jgummersall) convert to new user token client provider when available
try {
tokenExchangeResponse = await tokenProvider.exchangeToken(
context,
this.oAuthConnectionName,
context.activity.channelId,
{ token: tokenExchangeRequest.token }
const userTokenClient = context.turnState.get<UserTokenClient>(
(context.adapter as CloudAdapterBase).UserTokenClientKey
);
if (userTokenClient) {
tokenExchangeResponse = await userTokenClient.exchangeToken(
context.activity.from.id,
this.oAuthConnectionName,
context.activity.channelId,
{ token: tokenExchangeRequest.token }
);
} else if (ExchangeToken.check(context.adapter)) {
tokenExchangeResponse = await context.adapter.exchangeToken(
context,
this.oAuthConnectionName,
context.activity.channelId,
{ token: tokenExchangeRequest.token }
);
} else {
new Error('Token Exchange is not supported by the current adapter.');
}
} catch (_err) {
// Ignore Exceptions
// If token exchange failed for any reason, tokenExchangeResponse above stays null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

const assert = require('assert');
const { TurnContext } = require('botbuilder-core');
const sinon = require('sinon');
const { v4: uuid } = require('uuid');

Expand All @@ -13,6 +14,7 @@ const {
TestAdapter,
TestFlow,
tokenExchangeOperationName,
CloudAdapterBase,
} = require('../..');

const connectionName = 'connectionName';
Expand Down Expand Up @@ -183,4 +185,67 @@ describe('TeamsSSOTokenExchangeMiddleware', function () {
assert.strictEqual(logic.callCount, 1);
});
});

describe('exchangedToken', function () {
beforeEach(function () {
this.sandbox = sinon.createSandbox();
});

afterEach(function () {
this.sandbox.restore();
});
it('exchange token with CloudAdapter', async function () {
class TestCloudAdapter extends CloudAdapterBase {}
const conversation = TestAdapter.createConversation('Convo1');
const adapter = new TestCloudAdapter({});
const context = new TurnContext(adapter, {
channelId: Channels.Msteams,
name: tokenExchangeOperationName,
from: conversation.user,
conversation: conversation.conversation,
value: {
token: fakeExchangeableItem,
id: exchangeId,
connectionName,
},
});

const exchangeToken = this.sandbox.stub().returns(Promise.resolve({ token: fakeExchangeableItem }));
const logic = this.sandbox.stub();

context.turnState.set(adapter.UserTokenClientKey, { exchangeToken });
const middleware = new TeamsSSOTokenExchangeMiddleware(new MemoryStorage(), connectionName);
await middleware.onTurn(context, logic);

sinon.assert.calledOnce(exchangeToken);
sinon.assert.calledOnce(logic);
});

it('exchange token with BotFrameworkAdapter', async function () {
const conversation = TestAdapter.createConversation('Convo1');
const adapter = new TestAdapter(conversation);
const context = new TurnContext(adapter, {
channelId: Channels.Msteams,
name: tokenExchangeOperationName,
from: conversation.user,
conversation: conversation.conversation,
value: {
token: fakeExchangeableItem,
id: exchangeId,
connectionName,
},
});

const exchangeToken = this.sandbox
.stub(adapter, 'exchangeToken')
.returns(Promise.resolve({ token: fakeExchangeableItem }));
const logic = this.sandbox.stub();

const middleware = new TeamsSSOTokenExchangeMiddleware(new MemoryStorage(), connectionName);
await middleware.onTurn(context, logic);

sinon.assert.calledOnce(exchangeToken);
sinon.assert.calledOnce(logic);
});
});
});

0 comments on commit fbd66a2

Please sign in to comment.