sp-dev-fx-webparts/samples/react-bot-framework-secure
Hugo Bernier 4c0f65c780 Fixed readmes for consistency 2020-11-07 11:37:44 -05:00
..
assets V1.0 2020-11-06 17:29:14 +08:00
bot Fixed readmes for consistency 2020-11-07 11:37:44 -05:00
webpart Fixed readmes for consistency 2020-11-07 11:37:44 -05:00
README.md Fixed readmes for consistency 2020-11-07 11:37:44 -05:00

README.md

SharePoint web part sample with bot framework - Secure

Summary

Web parts is a special kind of SharePoint controls that can be supported by the Bot Framework. This sample will show you how to embed a Bot Framework bot into a SharePoint web site with security consideration.

There are two parts included in this sample:

  1. An echo bot sample
  2. A web part sample

The web part sample embeds the echo bot by using a webchat. As web part code is running on client side, web chat security needs to be taken into consideration. This sample shows how to secure your conversation including:

  • Use Direct Line token instead of Direct Line secret
  • Tamper-proof user: for user id, generate it inside client side and detect if the client has changed the user ID and reject the change.

This demo does not include any threat models and is designed for educational purposes only. When you design a production system, threat-modelling is an important task to make sure your system is secure and provide a way to quickly identify potential source of data breaches. IETF RFC 6819 and OAuth 2.0 for Browser-Based Apps is a good starting point for threat-modelling when using OAuth 2.0.

react-bot-framework-secure

Used SharePoint Framework Version

1.0

Applies to

Prerequisites

  • Node.js version 10.19 (Node.js v9.x, v11.x, and v12.x are not currently supported with SharePoint Framework development)

    # determine node version
    node --version
    

Solution

Solution Author(s)
webpart STCA BF Channel and ABS (stcabfchannel@microsoft.com)
Stephan Bisser (@stephanbisser, bisser.io)
bot STCA BF Channel and ABS (stcabfchannel@microsoft.com)

Version history

Version Date Comments
1.0 Nov 10, 2020 Initial release

Disclaimer

THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.


Minimal Path to Awesome

Enlist

  • Clone the repository

    git clone https://github.com/pnp/sp-dev-fx-webparts.git
    
  • In a terminal, navigate to sp-dev-fx-webparts

    cd sp-dev-fx-webparts
    
  • Navigate to the folder containing this sample

    cd samples
    cd react-bot-framework-secure
    

Setup bot

  • Go to ./bot

  • Install modules

    npm install
    
  • Start the bot. You can use emulator to verify whether the bot works

    npm start
    
  • Register connections. You can get it done by deploy your bot to Azure. Save your bot service endpoint like: "https://YOUR_BOT.azurewebsites.net". Save your AAD Id as YOUR_APP_ID and secret as YOUR_APP_PSW also.

  • Connect to direct line, copy one of the Secret Key values as YOUR_DIRECT_LINE_SECRET and store this for later. This is your Direct Line Secret.

  • Add DirectLineSecret to an .env config file under ./bot

    MicrosoftAppId=YOUR_APP_ID
    MicrosoftAppPassword=YOUR_APP_PSW
    DirectLineSecret=YOUR_DIRECT_LINE_SECRET
    
  • Restart your bot in local or redeploy your bot with new config.

Setup web part

  • Go to ./webpart

  • Install modules

    npm install
    
  • Start web part

    gulp serve
    

    Now web part is running locally in https://localhost:4321.

  • (Opt.) Publish the bot: follow the steps outlined in the Deploy your bot article.

  • (Opt.) Config CORS
    CORS must be set on bot app service to enable SharePoint client to get resource from bot service. Follow these steps to add your workbench to bot app service CORS configuration:

    1. Go to your azure portal
    2. Navigate to your bot app service, search for CORS settings
    3. Add https://localhost:4321 and https://<YOUR_SITE>.sharepoint.com to CORS origins
  • Config bot endpoint
    Add the web part, set bot endpoint to https://localhost:4321 (local) or https://YOUR_BOT.azurewebsites.net (remote), refresh this page, then you can successfully connect bot with SharePoint.

Features

Web Chat integration with security consideration

The SharePoint component will integrate bot with react Web Chat component.

public render(): React.ReactElement<IBotFrameworkChatv4Props> {
    return (
        <div className={styles.botFrameworkChatv4} style={{ height: 700 }}>
            <ReactWebChat directLine={directLine} styleOptions={styleSetOptions} />
        </div>
    );
}

Inside Web Chat, direct line will be used to connect to Bot Service. On Bot Service side, one more endpoint directline/token will be added besides api/messages, which will accept userId passed from client side and return back direct line token.

For production, this endpoint should also verify if the incoming request is authorized.

server.post('/directline/token', (req, res) => {
    const secret = settings.parsed.DirectLineSecret;
    const authorization = `Bearer ${secret}`;

    const userId = 'dl_' + GetUserId((req.body || {}).user);
    const options = {
        method: 'POST',
        uri: 'https://directline.botframework.com/v3/directline/tokens/generate',
        body: JSON.stringify({ user: { id: userId} }),
        headers: { 'Authorization': authorization, 'Content-Type': 'application/json'}
        };+

    request.post(options, (error, response, body) => {
        if (!error && response.statusCode < 300) {
            res.status(response.statusCode);
            if (body) { res.send(JSON.parse(body)) }
        } else {
            res.status(500);
            res.send('Call to retrieve token from DirectLine failed');
        }
        res.end();
    });
});

On web part side, it will fetch direct line token from bot service side with SharePoint userId then build up the web chat component. The UserId should be encrypted so it won't be easy to get other user's token by bot endpoint.

useEffect(() => {
    const userId = props.context.pageContext.user.loginName;
    generateToken(props.botEndpoint, md5(userId)).then((token: string) => {
        if (token) {
          setDirectLine(createDirectLine({ token }));
        }
    });
}, []);

And enable "Enhanced authentication options" can help detect client user Id change then reject the change: bot framework client web part
For how to find this option, please refer connect to direct line.

Further reading