Skip to content

Commit

Permalink
[SSO] [Port] support for SSO to parent and child bot projects for man…
Browse files Browse the repository at this point in the history
…ual testing (#1870)

* [SSO] [Port] support for SSO to parent and child bot projects ofr manual testing

* add a readme that links to the c# readme

Co-authored-by: Swagat Mishra <swagatm@microsoft.com>
Co-authored-by: Carlos Castro <carlosscastro@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 7, 2020
1 parent 49a49af commit c6baa19
Show file tree
Hide file tree
Showing 11 changed files with 314 additions and 28 deletions.
2 changes: 2 additions & 0 deletions libraries/testskills/ReadMeForSSOTesting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
For steps on how to test SSO using the skillParent and skillChild samples, please refer to the [ReadMe for C#](https://github.com/microsoft/botbuilder-dotnet/blob/master/tests/Skills/ReadMeForSSOTesting.md)
You will need to add your bot specific secrets like appId and password to the .env files instead of the appsettings.json as mentioned the C# ReadMe.
3 changes: 3 additions & 0 deletions libraries/testskills/skillchild/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MicrosoftAppId=
MicrosoftAppPassword=
ConnectionName=
37 changes: 35 additions & 2 deletions libraries/testskills/skillchild/childBot.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,47 @@ const { ActivityHandler } = require('botbuilder');

class ChildBot extends ActivityHandler {

constructor() {
constructor(conversationState, userState, dialog) {
super();
if (!conversationState) throw new Error('[ChilidBot]: Missing parameter. conversationState is required');
if (!userState) throw new Error('[ChilidBot]: Missing parameter. userState is required');
if (!dialog) throw new Error('[ChilidBot]: Missing parameter. dialog is required');

this.conversationState = conversationState;
this.userState = userState;
this.dialog = dialog;

this.onMessage(async (context, next) => {
await context.sendActivity('hello from child');
if(context.activity.channelId !== 'emulator') {
if(context.activity.text === 'skill login') {
await this.conversationState.load(context, true);
await this.userState.load(context, true);
await this.dialog.run(context, this.conversationState.createProperty('DialogState'));
}
else if(context.activity.text === 'skill logout') {
await context.adapter.signOutUser(context, process.env.ConnectionName);
context.sendActivity('logout from child bot successful');
}
}
else {
await context.sendActivity('hello from child');
}
await next();
});
}

async run(context) {
await super.run(context);

await this.conversationState.saveChanges(context, false);
await this.userState.saveChanges(context, false);
}

async onSignInInvoke(context) {
await this.conversationState.load(context, true);
await this.userState.load(context, true);
await this.dialog.run(context, this.conversationState.createProperty('DialogState'));
}
}

module.exports.ChildBot = ChildBot;
19 changes: 16 additions & 3 deletions libraries/testskills/skillchild/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@

const restify = require('restify');
const path = require('path');

const { BotFrameworkAdapter } = require('botbuilder');
const { BotFrameworkAdapter, ConversationState, MemoryStorage, UserState } = require('botbuilder');
const { ChildBot } = require('./childBot');
const { MainDialog } = require('./mainDialog');

const adapter = new BotFrameworkAdapter();
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE});

const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
})

// Create HTTP server
const server = restify.createServer();
Expand All @@ -13,7 +21,12 @@ server.listen(3979, function() {
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
});

const bot = new ChildBot();
const memoryStorage = new MemoryStorage();
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);

const dialog = new MainDialog();
const bot = new ChildBot(conversationState, userState, dialog);

// Listen for incoming activities and route them to your bot main dialog.
server.post('/api/messages', (req, res) => {
Expand Down
49 changes: 49 additions & 0 deletions libraries/testskills/skillchild/mainDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { ComponentDialog, DialogSet, DialogTurnStatus, OAuthPrompt, WaterfallDialog } = require('botbuilder-dialogs');

const OAUTH_PROMPT = 'oAuthPrompt';
const MAIN_WATERFALL_DIALOG = 'mainWaterfallDialog';

class MainDialog extends ComponentDialog {
constructor() {
super('MainDialog');
this.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.ConnectionName,
text: 'Sign In to AAD',
title: 'Sign In'
}))
.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.signInStep.bind(this),
this.showTokenResponse.bind(this)
]));
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}

async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);

const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}

async signInStep(step) {
return step.beginDialog(OAUTH_PROMPT);
}

async showTokenResponse(step) {
const tokenResponse = step.result;
if(tokenResponse) {
console.log(`Skill: your token is ${ tokenResponse.token }`)
}
else {
console.log('Skill: No token response from OAuthPrompt');
}

return await step.endDialog();
}
}

module.exports.MainDialog = MainDialog;
1 change: 1 addition & 0 deletions libraries/testskills/skillchild/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"license": "ISC",
"dependencies": {
"botbuilder": "4.1.6",
"botbuilder-dialogs": "4.1.6",
"restify": "^8.5.1"
}
}
4 changes: 4 additions & 0 deletions libraries/testskills/skillparent/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MicrosoftAppId=
MicrosoftAppPassword=
ConnectionName=
SkillMicrosoftAppId=
21 changes: 17 additions & 4 deletions libraries/testskills/skillparent/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@

const restify = require('restify');
const path = require('path');

const { BotFrameworkAdapter } = require('botbuilder');
const { BotFrameworkAdapter, ConversationState, MemoryStorage, UserState } = require('botbuilder');;
const { ParentBot } = require('./parentBot');
const { MainDialog } = require('./mainDialog');

const adapter = new BotFrameworkAdapter();
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE});

const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});

// Create HTTP server
const server = restify.createServer();
server.listen(3978, function() {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log(`\n${ server.name } listening to ${ server.url } with id ${ process.env.MicrosoftAppId } and password ${ process.env.MicrosoftAppPassword }`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
});

const bot = new ParentBot();
const memoryStorage = new MemoryStorage();
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);

const dialog = new MainDialog();
const bot = new ParentBot(conversationState, userState, dialog);

// Listen for incoming activities and route them to your bot main dialog.
server.post('/api/messages', (req, res) => {
Expand Down
49 changes: 49 additions & 0 deletions libraries/testskills/skillparent/mainDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { ComponentDialog, DialogSet, DialogTurnStatus, OAuthPrompt, WaterfallDialog } = require('botbuilder-dialogs');

const OAUTH_PROMPT = 'oAuthPrompt';
const MAIN_WATERFALL_DIALOG = 'mainWaterfallDialog';

class MainDialog extends ComponentDialog {
constructor() {
super('MainDialog');
this.addDialog(new OAuthPrompt(OAUTH_PROMPT, {
connectionName: process.env.ConnectionName,
text: 'Sign In to AAD',
title: 'Sign In'
}))
.addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
this.signInStep.bind(this),
this.showTokenResponse.bind(this)
]));
this.initialDialogId = MAIN_WATERFALL_DIALOG;
}

async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);

const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}

async signInStep(step) {
return step.beginDialog(OAUTH_PROMPT);
}

async showTokenResponse(step) {
const tokenResponse = step.result;
if(tokenResponse) {
await step.context.sendActivity(`your token is ${ tokenResponse.token }`);
}
else {
await step.context.sendActivity('No token response from OAuthPrompt');
}

return await step.endDialog();
}
}

module.exports.MainDialog = MainDialog;
1 change: 1 addition & 0 deletions libraries/testskills/skillparent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"botbuilder": "4.1.6",
"botframework-connector": "4.1.6",
"botbuilder-dialogs": "4.1.6",
"restify": "^8.5.1"
}
}
Loading

0 comments on commit c6baa19

Please sign in to comment.