We have a scenario where a user would first login to web application before starting a conversation with Azure Bot.
My question is how do we ensure bot will only allow user to ask financial questions related to his own accounts considering the bot is capable of answer questions related to financial holding of the person logged in.
Basically is there a way to pass principal object to the bot before the conversation starts. If yes how do we pass those details.
The BotFramework currently does not support single sign-on; however, the BotFramework Web Chat Development team has recommended different approaches to create a single sign-on experience and is currently working on developing a sample.
The main approach recommends piggybacking the authentication token on every outgoing message by adding it to the activity's channel data. To do this, you can create a custom middleware that appends the additional data. Take a look at the code snippet below.
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/POST_ACTIVITY') {
// The channelData submitted here is very similar to HTTP cookies and vulnerable to forgery attack.
// Make sure you use signature to protect it and verify the signature on the bot side.
// To minimize unexpected behaviors, we recommend to treat the "action" object as if it is immutable.
// We use simple-update-in package to update "action" with partial deep cloning.
action = window.simpleUpdateIn(action, ['payload', 'activity', 'channelData', 'token'], () => token);
}
return next(action);
}
);
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
// We will use a custom version of Redux store, which we added middleware to handle backchannel messages.
store
}, document.getElementById('webchat'));
On the bot side, you can retrieve the token from the channel data and use it to make various requests. For more details on adding data to outgoing activities, take a look at this sample.
For more details regarding recommended approaches, take a look at this issue on GitHub. The Web Chat Development team is also using it to track the progress of the sample.
Hope this helps.
Related
I want to call a messaging extension (with action command) and access Graph API via a bot for getting different resources of the channel (e.g. retrieve all messages or get replies for my message).
In the examples from Microsoft it is stated as a prerequisite that I have to do the "Bot channels registration" so that the access of the bot to the Graph API via OAuth2 works.
Do I really need this channel registration? Or is there another way?
As a test, I had created a azure free trial, with which I performed the "Bot channels registration" and could also save the ID and secret for the Graph Api access in the registration. With this I had success. Now the 30 days testing period is over and I'm interested in whether it would work without.
Thanks for your help
Update:
Thats my code to initialize graph api:
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(AppId)
.WithClientSecret(AppSecret)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{Tenant}"))
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult authenticationResult = await app.AcquireTokenForClient(scopes).ExecuteAsync();
var graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) =>
{
requestMessage
.Headers
.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
return Task.FromResult(0);
}));
For OAuth authentication, you need to register the bot with azure for sure.
I have created a proactive bot that basically asks certain questions to a user when a user starts conversation with the bot. The bot is deployed in Microsoft Teams environment. Is there any way that i can send automated message to a bot in a channel? I know messages can be sent using powershell by utilizing webhook url exposed by a particular team or using MS Flow. But I want to mention bot (e.g. #mybothandle) in the message so the bot starts asking questions by itself than requiring the user to start the conversation (by mentioning the bot manually) but not finding the way to mention.
Your suggestions are welcome.
Basically you want to message the user directly at a specific point in time (like 24 hours later). I'm doing this in a few different bots, so it's definitely possible. The link that Wajeed has sent in the comment to your question is exactly what you need - when the user interacts with your bot, you need to save important information like the conversation id, conversation type, service url, and To and From info. You can store this, for instance, in a database, and then you can actually have a totally separate application make the call AS IF IT WAS your bot. In my bots, for example, I have the bot hosted in a normal host (e.g. Azure Website) but then have an Azure Function that sends the messages, for example, 24 hours later. It just appears to the user as if it was a message from the bot, like normal.
You will also need the Microsoft App ID and App Password for your bot, which you should have already (if not, it's in the Azure portal).
In your "sending" application, you're going to need to create an instance of Microsoft. Bot.Connector.ConnectorClient, like follows:
var Connector = new ConnectorClient(serviceUrl, microsoftAppId: credentialProvider.AppId, microsoftAppPassword: credentialProvider.Password);
You also need to "trust" the service url you're calling, like this:
MicrosoftAppCredentials.TrustServiceUrl(serviceURL);
Then you create an instance of Microsoft.Bot.Schema.Activity, set the required properties, and send it via the connector you created:
var activity = Activity.CreateMessageActivity();
activity.From = new ChannelAccount([FromId], [FromName];
activity.Recipient = new ChannelAccount([ToId], [ToName]);
activity.Conversation = new ConversationAccount(false, [ConversationType], [ConversationId]);
activity.Conversation.Id = [ConversationId];
activity.Text = "whatever you want to send from the bot...";
Connector.Conversations.SendToConversationAsync((activity as Activity)).Wait();
All the items in square braces are what you get from the initial conversation the user is having with the bot, except that the From and To are switched around (when the user sends your bot a message, the user is the FROM and your Bot is the TO, and when the bot is sending you switch them around.
Hope that helps
To all Future Visitors, Microsoft Graph API (Beta) now provides a way to send message and mention the bot/user using following endpoint:
https://graph.microsoft.com/beta/teams/{group-id-for-teams}/channels/{channel-id}/messages
Method: POST
Body:
"body": {
"contentType": "html",
"content": "Hello World <at id=\"0\">standupbot</at>"
},
"mentions": [
{
"id": 0,
"mentionText": "StandupBot",
"mentioned": {
"application": {
"id": "[my-bot-id]",
"displayName": "StandupBot",
"applicationIdentityType": "bot"
}
}
}
]
}
However, there is a bug that bot doesn't respond when receives the message:
Bot is not responding to #Mention when sending message using Graph API
I have to design a bot that can answer what my app users are asking about their project. Answers will be the implementations of certain APIs. These APIs that my bot will be using to give answers are secured by user-specific authentication tokens. As of now, I have written a bot using Microsoft bot framework and LUIS that understands certain utterances and can give answers with calling project APIS.I am confused about how to do these things :
How to pass user authentication token to bot? This toke is generated using user credentials (usename+password). Inside my bot code, I can't use username/password for generating the token.I need to pass them from client app only.
How to pass project Id to the bot about which user is asking the question? The user might be calling the name of the project, or will select the project from a list. The bot should be intelligent enough to change answers based on project Id.
As of now, I am handing second part using LUIS utterances + Entity combination. So my question(utterance is ): "tell me what's new in {projectid}" where projectid is my project entity.
But for the first question, I am still looking for the solution. Please suggest.
You will need few modification in your bot to use DirectLine API instead of webchat. Directline API gives you flexibility to send your own data to Bot. There are few reserved properties inside Activity.From from which you can read your data.
var userProperties = [];
userProperties.push({
projectId:
{Project_Id_Will_Be_Sent_Using_This},
UserToken:
{User_Generated_Token}
});
BotChat.App({
directLine: { secret: 'BOT-SECRET-KEY' },
user: { id: '', name:'', properties:userProperties },
bot: { id: 'YOUR-BOT-ID' },
resize: 'detect',
}, document.getElementById("bot"));
Please revert if you need any help around this.
How to secure the traffic from Microsoft Teams to a bot, so that bot could be answering on company specific questions / discussions and would not need to be exposed as anonymous WebAPI?
Bot integration to Teams UIs is easy from bot framework side, but right now there's no documentation for how to isolate bot only for specific enterprise.
Business case - We want to build enterprise specific bot, which could answer questions only specific to that particular enterprise where the questions are coming from. Technically this could be done with app-only access to SharePoint or Microsoft Graph, but we cannot expose this kind of WebAPI anonymously for Internet.
Any design patterns for this?
This is now possible, and I've actually even implemented it for Hubot in CoffeeScript and Node.JS. What I've described below is what it would look like in JavaScript/Node.JS.
Define an environment variable that, when set, filters for a particular tenant ID, OFFICE_365_TENANT_FILTER. (Doing it this way is a handy way of turning this feature on in production but not necessarily during development.)
For Microsoft Teams, the Office 365 tenant ID can be found here: session.message.sourceEvent.tenant.id.
The most elegant way to do it is to check for the tenant ID as middleware, and just drop further processing of the message if the filter is set and it doesn't match:
// [...]
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
var bot = new builder.UniversalBot(connector);
// Middleware to check for OFFICE_365_TENANT_FILTER and only continue processing if it matches.
// If OFFICE_365_TENANT_FILTER is not specified, do nothing.
bot.use({
botbuilder: function(session, next) {
var targetTenant = typeof(process.env.OFFICE_365_TENANT_FILTER) !== "undefined" ? process.env.OFFICE_365_TENANT_FILTER : null;
var currentMsgTenant = typeof(session.message.sourceEvent.tenant) !== "undefined" ? session.message.sourceEvent.tenant.id : null;
if (targetTenant !== null) {
if (targetTenant == currentMsgTenant) {
next();
}
else {
console.log("MS Teams: Attempted access from a different Office 365 tenant (" + currentMsgTenant + "): message rejected");
}
}
else {
next();
}
}
});
// [...]
Here's how to do this in C#, the SDK exposes the TenantFilter that allows you to add this action filter to the controller class as shown below.
using Microsoft.Bot.Connector.Teams;
namespace Microsoft.Teams.Samples.HelloWorld.Web.Controllers
{
[BotAuthentication, TenantFilter]
public class MessagesController : ApiController
{
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody] Activity activity)
The tenant filter will take a comma separated list of tenantIds that will need to be placed in the web.config
<configuration>
<appSettings>
<!--other settings-->
<add key="AllowedTenants" value="*TenantId1,TenantId2,...*"/>
Find your Office 365 tenant ID shows how you can do it through PowerShell.
It is not currently possible to know the tenant-id of the user chatting with the bot right away, unless the bot authenticates the user first. Please take a look at AuthBot. It illustrates how to send a sign-in link to a user and authenticate the user against AAD.
Although not exactly what you are looking for, you can create custom bots which will be scoped to individual Teams.
The security key/HMAC auth will prevent others from accessing the API. With the drawback that you will have to configure the bot with a separate security token for every Team where you want to use it.
I am building site that allows users to signup for multiple subscriptions. The Parse.com / Stripe API we use allows me to create multiple subscriptions for each user. However, if a user has more than one subscription, and I attempt to cancel any of them, I get an error that the user has more than one subscription and that I must identify which subscription I am referring to. The problem is, that I do attempt to pass the subscription ID to into the API (see below) but it just seems to get ignored. Stripe clearly supports this second parameter in their API, but the Parse documentation does not show a second "subscriptionId" parameter.
The following Parse Cloud Code (which works perfectly as long as the user has only one subscription)
Parse.Cloud.define("cancelStripeSubscription", function(request, response) {
Stripe.Customers.cancelSubscription(request.params.customerId, request.params.subscriptionId, true, {
success: function(httpResponse) {
response.success("Cancellation Complete");
},
error: function(httpResponse) {
response.error("Error: " + httpResponse.message);
}
});
});
Here is the relevant Parse/Stripe Cloud Code API - https://parse.com/docs/js/api/symbols/Stripe.Customers.html#.cancelSubscription
Here is the equivalent Stripe API clearly showing a second "subscriptionId" parameter. https://stripe.com/docs/api/node#cancel_subscription
I'm hoping that the Parse/Stripe module does support multiple subscriptions.
Thanks for any help!
Unfortunately, Parse's Stripe API library is pretty old and was built against an old version of the API when only 1 subscription was possible. You'd either just have to do 1 subscription per customer or generate the web request to Stripe's API yourself not using the library.