Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JS] Add details to README in certificate samples #427

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add details to SNI sample
  • Loading branch information
JhontSouth committed Jun 6, 2024
commit 215db8341bc311859ea92db0c2670960e54dd79e
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ An SSL/TLS certificate is a digital object that allows systems to verify identit

![Upload Cer Certificate](Images/KeyVault/UploadCerCertificate.png)

6. In the sample code, go to the [Startup](Startup.cs) class and uncomment the line of code that reads the keyvault certificate and verify that the keyvault credentials are completed in the [appsettings](appsettings.json) file.
6. In the sample code, go to the [Startup](Startup.cs) class and uncomment the line of code that reads the keyvault certificate and verify that the keyvault credentials are completed in the [.env](.env) file.
Be sure to comment out or remove the lines of code that use local certificate to avoid errors.
> NOTE: Here the value of MicrosoftAppId and CertificateThumbprint are also needed to generate the credentials.

Expand Down
2 changes: 0 additions & 2 deletions samples/javascript_nodejs/85.bot-authentication-sni/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
MicrosoftAppType=
MicrosoftAppId=
MicrosoftAppTenantId=
CertificateThumbprint=
KeyVaultName=
CertificateName=
180 changes: 121 additions & 59 deletions samples/javascript_nodejs/85.bot-authentication-sni/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,114 +2,174 @@

Bot Framework v4 bot authentication using Subject Name/Issuer

This bot has been created using [Bot Framework](https://dev.botframework.com/), is shows how to use the bot authentication capabilities of Azure Bot Service. In this sample, we use a local or KeyVault certificate and the MSAL Subject Name/Issuer configuration to create the Bot Framework Authentication.
This bot has been created using Bot Framework, it shows how to use the bot authentication capabilities of Azure Bot Service. In this sample, we use a local or KeyVault certificate and the MSAL Subject Name/Issuer configuration to create the Bot Framework Authentication.
>NOTE: Microsoft's first-party resources are required to test this sample.

## Interacting with the bot

This sample uses the bot authentication capabilities of Azure Bot Service, providing features to make it easier to develop a bot that authenticates users using digital security certificates. You just need to provide the certificate data linked to the managed identity and run the bot, then communicate with it to validate its correct authentication.


## Prerequisites

- [Node.js](https://nodejs.org) version 10.14 or higher

```bash
# determine node version
node --version
```
```bash
# determine node version
node --version
```

- [Ngrok](https://ngrok.com/) latest version.

## SSL/TLS certificate

An SSL/TLS certificate is a digital object that allows systems to verify identity and subsequently establish an encrypted network connection with another system using the Secure Sockets Layer/Transport Layer Security (SSL/TLS) protocol. Certificates are issued using a cryptographic system known as public key infrastructure (PKI). PKI allows one party to establish the identity of another through the use of certificates if they both trust a third party, known as a certificate authority. SSL/TLS certificates therefore function as digital identity documents that protect network communications and establish the identity of websites on the Internet as well as resources on private networks.

## Subject Name and Issuer (SNI) Authentication

Certificate Subject Name and Issuer (SNI) based authentication is currently available only for Microsoft internal (first-party) applications. External (third-party) apps cannot use SNI because SNI is based on the assumption that the certificate issuer is the same as the tenant owner. This can be guaranteed for some first-party tenants, but not for third-party. So there are no plans to bring SNI to third-party apps. For more details about this feature and code examples see this [SNI issue](https://github.com/AzureAD/microsoft-authentication-library-for-python/issues/60) and a [wiki page](https://aadwiki.windows-int.net/index.php?title=Subject_Name_and_Issuer_Authentication).

## To try this sample

- Setup ngrok
1. Run ngrok - point to port 3978

```bash
ngrok http --host-header=rewrite 3978
```

- Setup a Bot
1. Register a bot with Azure Bot Service, following the instructions [here](https://docs.microsoft.com/azure/bot-service/bot-service-quickstart-registration?view=azure-bot-service-3.0).

2. While registering the bot, use `https://<your_tunnel_domain>/api/messages` as the messaging endpoint.
> NOTE: When you create your bot you will create a Microsoft App ID - make sure you keep this for later.

- Clone the repository

```bash
git clone https://github.com/microsoft/botbuilder-samples.git
```
```bash
git clone https://github.com/microsoft/botbuilder-samples.git
```

- In a terminal, navigate to `samples/javascript_nodejs/85.bot-authentication-sni`
- Configure the SSL/TSL certificate. This sample requires an existing certificate issued by an integrated CA. We have two options to configure it in the bot. Below is a step-by-step description of each one:

```bash
cd samples/javascript_nodejs/85.bot-authentication-sni
```
### Using local environment
- This option requires the following app settings variables:

- Install modules
- MicrosoftAppId: App Id of your bot.

```bash
npm install
```
- MicrosoftAppTenantId: Tenant Id to which your bot belongs(optional).

- Set environment variables
1. Intall and configure [OpenSSL](https://www.openssl.org/source/) with the latest version
- Download the latest version source and add the folder to the [environment variables](https://www.java.com/en/download/help/path.html) path.
```bash
setx path "%path%;<OpenSSL path here>
i.e
setx path "%path%;C:\Program Files\openssl-3.3.0"
```

- MicrosoftAppType: Type of the App.
2. Generate a _pem_ file without key:
- If your certificate is in _pfx_ format execute the following command:
```
OpenSSL pkcs12 -in .\<certificate-name>.pfx -out <certificate-name>.pem –nodes -nokeys
```

- MicrosoftAppId: App Id of your bot.
![Pem File Command No Key](Images/Local/PemCommandNoKey.png)

- MicrosoftAppTenantId: Tenant Id to which your bot belongs.
- If your certificate is in _pem_ format and includes the key, execute the following command to remove the key:
```
OpenSSL pkcs12 -in .\<certificate-name>.pem -export -out .\<certificate-without-key-name>.pem -nokeys
```

- CertificateThumbprint: Certificate thumbprint.
![Pem Export No Key](Images/Local/PemExportNoKey.png)

- KeyVaultName: Name of the KeyVault containing the certificate.
3. Upload the generated certificate to the Azure app registration.

- CertificateName: Name of the certificate in the KeyVault.
![Certificate Upload](Images/Local/CertificateUpload.png)

- Start the bot
4. To read the certificate in the bot, the _pem_ file must include the key, then if your certificate is in _pfx_ format go to the certificate location and run the following command to generate a _pem_ file with key:

```bash
npm start
```
```
OpenSSL pkcs12 -in .\<certificate-name>.pfx -out <certificate-with-key-name>.pem –nodes
```

## Testing the bot using Bot Framework Emulator
![Pem Command With Key](Images/Local/PemCommandWithKey.png)

[Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
5. In the sample code, go to the [index](index.js) file and uncomment the line of code that reads the local certificate and write the name of the certificate in _pem_ format inside the _CreateFromPemFile_ method.
Be sure to comment out or remove the lines of code that use Azure KeyVault to avoid errors.

> NOTE: Here the value of MicrosoftAppId is needed to generate the credentials.

- Install the latest Bot Framework Emulator from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)
![Certificate Reading](Images/Local/CertificateReading.png)

### Connect to the bot using Bot Framework Emulator
### Using KeyVault
- This option requires the following app settings variables:

- Launch Bot Framework Emulator
- MicrosoftAppId: App Id of your bot.

- File -> Open Bot
- KeyVaultName: Name of the KeyVault containing the certificate.

- Enter a Bot URL of `http://localhost:3978/api/messages`
- CertificateName: Name of the certificate in the KeyVault.

## Interacting with the bot
- MicrosoftAppTenantId: Tenant Id to which your bot belongs(optional).

This sample uses the bot authentication capabilities of Azure Bot Service, providing features to make it easier to develop a bot that authenticates users using digital security certificates. You just need to provide the certificate data linked to the managed identity and run the bot, then communicate with it to validate its correct authentication.
1. Import the certificate under the Certificates section, hit on Generate/Import, complete the form, and upload the certificate.

## SSL/TLS certificate
![Generate Import Certificate](Images/KeyVault/GenerateImportCertificate.png)
![Import Certificate](Images/KeyVault/ImportCertificate.png)

An SSL/TLS certificate is a digital object that allows systems to verify identity and subsequently establish an encrypted network connection with another system using the Secure Sockets Layer/Transport Layer Security (SSL/TLS) protocol. Certificates are issued using a cryptographic system known as public key infrastructure (PKI). PKI allows one party to establish the identity of another through the use of certificates if they both trust a third party, known as a certificate authority. SSL/TLS certificates therefore function as digital identity documents that protect network communications and establish the identity of websites on the Internet as well as resources on private networks.
2. Go to the details of the certificate and download it in _CER_ format to avoid the export of the private key.

![Certificate Details](Images/KeyVault/CertificateDetails.png)
![Download Certificate](Images/KeyVault/DownloadCertificate.png)

## How to create an SSL/TLS certificate
>NOTE: If you downloaded it in _PFX/PEM_ format, it will be neccesary to remove the private key by executing one the following commands:
```
OpenSSL pkcs12 -in .\<certificate-name>.pfx -out <certificate-name>.pem –nodes -nokeys
OpenSSL pkcs12 -in .\<certificate-name>.pem -export -out .\<certificate-without-key-name>.pem -nokeys
```
![Pem File Command No Key](Images/Local/PemCommandNoKey.png)
![Pem Export No Key](Images/Local/PemExportNoKey.png)

There are two possible options to create SSL/TSL certificate. Below is a step-by-step description of each one:
3. Upload the certificate to the Azure app registration.

### Using local environment
![Upload Cer Certificate](Images/KeyVault/UploadCerCertificate.png)

1. Run the following command in a local PowerShell
4. In the sample code, go to the [index](index.js) file and uncomment the line of code that reads the keyvault certificate and verify that the keyvault credentials are completed in the [.env](.env) file.
Be sure to comment out or remove the lines of code that use local certificate to avoid errors.
> NOTE: Here the value of MicrosoftAppId is also needed to generate the credentials.

```
$cert = New-SelfSignedCertificate -CertStoreLocation "<directory-to-store-certificate>" -Subject "CN=<certificate-name>" -KeySpec KeyExchange
```
![Certificate Reading](Images/KeyVault/CertificateReading.png)

1. Then, type _Manage User Certificates_ in the Windows search bar and hit enter
1. In the current sample context, log into Azure to obtain the default credentials by executing the following command:
```
az login
```

2. The certificate will be located in the _user certificates_ folder, under _personal_ directory.
- Run the bot from a terminal or from Visual Studio:

3. Export the certificate to _pfx_ format including the key(The default location is _system32_ folder).
- In a terminal, navigate to `samples/javascript_nodejs/85.bot-authentication-sni`

4. Go to the certificate location and run the following command to generate a _pem_ file:
```bash
cd samples/javascript_nodejs/85.bot-authentication-sni
```

```
OpenSSL pkcs12 -in <certificate-name>.pfx -out c:\<certificate-name>.pem –nodes
```
- Install modules

5. Upload the generated certificate to the Azure app registration.
```bash
npm install
```

### Using KeyVault
- Start the bot

1. Create a KeyVault resource and assign _the KeyVault Administrator_ role to have permission to create a new certificate.
```bash
npm start
```

2. Under the Certificates section, hit on Generate/Import, complete the form, and create the certificate in PEM format.
## Testing the bot using Azure Bot

3. Go to the details of the certificate that you created and enable it.
Go to the Azure bot resource created previously, select the _Test in Web Chat_ option under the _Settings_ section and start talking to the bot.

4. Download the certificate in CER format and then upload it to the Azure app registration.
![Bot Conversation](Images/BotConversation.png)

## Deploy the bot to Azure

Expand All @@ -136,5 +196,7 @@ To learn more about deploying a bot to Azure, see [Deploy your bot to Azure](htt
- [Restify](https://www.npmjs.com/package/restify)

- [dotenv](https://www.npmjs.com/package/dotenv)

- [SSL/TLS certificates](https://www.digicert.com/tls-ssl/tls-ssl-certificates)

- [Subject Name and Issuer (SNI) Authentication](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Subject-Name-and-Issuer-(SNI)-Authentication)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 23 additions & 30 deletions samples/javascript_nodejs/85.bot-authentication-sni/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
// Licensed under the MIT License.

const path = require('path');
// const fs = require('fs');
const fs = require('fs');

Check failure on line 5 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

'fs' is assigned a value but never used
const { createPrivateKey } = require('crypto');
const dotenv = require('dotenv');
const restify = require('restify');
const msal = require('@azure/msal-node');
const { DefaultAzureCredential } = require('@azure/identity');
const { SecretClient } = require('@azure/keyvault-secrets');
const { MsalServiceClientCredentialsFactory } = require('botframework-connector');
const { CertificateServiceClientCredentialsFactory } = require('botframework-connector');

// Import required bot configuration.
const ENV_FILE = path.join(__dirname, '.env');
Expand All @@ -31,19 +31,17 @@
server.use(restify.plugins.bodyParser());

server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log(`\n${server.name} listening to ${server.url}`);

Check failure on line 34 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space(s) after '${'

Check failure on line 34 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space(s) before '}'

Check failure on line 34 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space(s) after '${'

Check failure on line 34 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space(s) before '}'
console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator');
console.log('\nTo talk to your bot, open the emulator select "Open Bot"');
});

const authorityUrl = 'https://login.microsoftonline.com/botframework.com';

// ---- Authenticate using key vault to obtain the certificate values.
// Create an Azure credential to authenticate.
const credential = new DefaultAzureCredential();

const vaultName = process.env.KeyVaultName;
const keyVaultUrl = `https://${ vaultName }.vault.azure.net`;
const keyVaultUrl = `https://${vaultName}.vault.azure.net`;

Check failure on line 44 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space(s) after '${'

Check failure on line 44 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space(s) before '}'

const certificateName = process.env.CertificateName;

Expand All @@ -52,32 +50,27 @@

// Assuming you've already created a Key Vault certificate,
// and that certificateName contains the name of your certificate.
const certificateSecret = await secretClient.getSecret(certificateName);

// Here we can find both the private key and the public certificate, in PKCS 12 format:
const certificateKey = certificateSecret.value;
const cert = (await secretClient.getSecret(certificateName)).value;

// ---- Authenticate using local certificate.
// const key = fs.readFileSync('{KeyPath}.pem', 'utf8');

// Extract x5c value from the key string to use the SNI authentication.
const x5cValue = certificateKey.split('-----BEGIN CERTIFICATE-----\n').pop().split('\n-----END CERTIFICATE-----')[0];
// //Read the certificate from the file
// const cert = fs.readFileSync('{KeyPath}.pem', 'utf8');

// Create a private key object from the certificate
var certificateKey = createPrivateKey(cert);
//Convert the private key object to a string format

Check failure on line 61 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space or tab after '//' in comment
const privateKey = certificateKey.export({
type: 'pkcs8', // Can also be 'pkcs1' depending on your format requirements
format: 'pem'
});

// Create client credentials using SNI authentication from MSAL.
const serviceClientCredentialsFactory = new MsalServiceClientCredentialsFactory(
const serviceClientCredentialsFactory = new CertificateServiceClientCredentialsFactory(
process.env.MicrosoftAppId,
new msal.ConfidentialClientApplication({
auth: {
clientId: process.env.MicrosoftAppId,
authority: authorityUrl,
clientCertificate: {
thumbprint: process.env.CertificateThumbprint,
privateKey: certificateKey,
x5c: x5cValue
}
}
})
);
cert,
privateKey,
process.env.MicrosoftAppTenantId
)

Check failure on line 73 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Missing semicolon

const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(process.env, serviceClientCredentialsFactory);

Expand All @@ -90,12 +83,12 @@
// NOTE: In production environment, you should consider logging this to Azure
// application insights. See https://aka.ms/bottelemetry for telemetry
// configuration instructions.
console.error(`\n [onTurnError] unhandled error: ${ error }`);
console.error(`\n [onTurnError] unhandled error: ${error}`);

Check failure on line 86 in samples/javascript_nodejs/85.bot-authentication-sni/index.js

View workflow job for this annotation

GitHub Actions / bot - javascript_nodejs/85.bot-authentication-sni

Expected space(s) after '${'

// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity(
'OnTurnError Trace',
`${ error }`,
`${error}`,
'https://www.botframework.com/schemas/error',
'TurnError'
);
Expand Down
Loading