From 9b6173682b83ae7f2e37334a87609edf0da8c454 Mon Sep 17 00:00:00 2001 From: Tracy Boehrer Date: Tue, 18 Jun 2024 10:02:18 -0500 Subject: [PATCH] Using CertificateServiceClientCredentialsFactory for SN+I sample --- .../AuthSNIBot.csproj | 2 +- .../Bots/AuthSNIBot.cs | 17 ++-- .../Bots/DialogBot.cs | 50 ---------- .../85.bot-authentication-sni/README.md | 97 ++++++------------- .../85.bot-authentication-sni/Startup.cs | 37 +++---- 5 files changed, 54 insertions(+), 149 deletions(-) delete mode 100644 samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/DialogBot.cs diff --git a/samples/csharp_dotnetcore/85.bot-authentication-sni/AuthSNIBot.csproj b/samples/csharp_dotnetcore/85.bot-authentication-sni/AuthSNIBot.csproj index b27dce8076..d3e9ce08cc 100644 --- a/samples/csharp_dotnetcore/85.bot-authentication-sni/AuthSNIBot.csproj +++ b/samples/csharp_dotnetcore/85.bot-authentication-sni/AuthSNIBot.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/AuthSNIBot.cs b/samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/AuthSNIBot.cs index fd8300485a..9bf8146852 100644 --- a/samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/AuthSNIBot.cs +++ b/samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/AuthSNIBot.cs @@ -11,21 +11,22 @@ namespace Microsoft.BotBuilderSamples { public class AuthSNIBot : ActivityHandler { + protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) + { + var replyText = $"Echo: {turnContext.Activity.Text}"; + await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken); + } + protected override async Task OnMembersAddedAsync(IList membersAdded, ITurnContext turnContext, CancellationToken cancellationToken) { - foreach (var member in turnContext.Activity.MembersAdded) + var welcomeText = "Hello and welcome!"; + foreach (var member in membersAdded) { if (member.Id != turnContext.Activity.Recipient.Id) { - await turnContext.SendActivityAsync(MessageFactory.Text("Welcome to the Bot with Subject Name/Issuer Authentication."), cancellationToken); + await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken); } } } - - protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) - { - var replyText = "Running dialog with bot authenticated"; - await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken); - } } } diff --git a/samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/DialogBot.cs b/samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/DialogBot.cs deleted file mode 100644 index 5136835d99..0000000000 --- a/samples/csharp_dotnetcore/85.bot-authentication-sni/Bots/DialogBot.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Bot.Builder; -using Microsoft.Bot.Builder.Dialogs; -using Microsoft.Bot.Schema; -using Microsoft.Extensions.Logging; - -namespace Microsoft.BotBuilderSamples -{ - // This IBot implementation can run any type of Dialog. The use of type parameterization is to allows multiple different bots - // to be run at different endpoints within the same project. This can be achieved by defining distinct Controller types - // each with dependency on distinct IBot types, this way ASP Dependency Injection can glue everything together without ambiguity. - // The ConversationState is used by the Dialog system. The UserState isn't, however, it might have been used in a Dialog implementation, - // and the requirement is that all BotState objects are saved at the end of a turn. - public class DialogBot : ActivityHandler where T : Dialog - { - protected readonly BotState ConversationState; - protected readonly Dialog Dialog; - protected readonly ILogger Logger; - protected readonly BotState UserState; - - public DialogBot(ConversationState conversationState, UserState userState, T dialog, ILogger> logger) - { - ConversationState = conversationState; - UserState = userState; - Dialog = dialog; - Logger = logger; - } - - public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) - { - await base.OnTurnAsync(turnContext, cancellationToken); - - // Save any state changes that might have occurred during the turn. - await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken); - await UserState.SaveChangesAsync(turnContext, false, cancellationToken); - } - - protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) - { - Logger.LogInformation("Running dialog with Message Activity."); - - // Run the Dialog with the new message Activity. - await Dialog.RunAsync(turnContext, ConversationState.CreateProperty(nameof(DialogState)), cancellationToken); - } - } -} diff --git a/samples/csharp_dotnetcore/85.bot-authentication-sni/README.md b/samples/csharp_dotnetcore/85.bot-authentication-sni/README.md index c7c293656a..3055589b05 100644 --- a/samples/csharp_dotnetcore/85.bot-authentication-sni/README.md +++ b/samples/csharp_dotnetcore/85.bot-authentication-sni/README.md @@ -21,91 +21,56 @@ This bot has been created using [Bot Framework](https://dev.botframework.com/), git clone https://github.com/microsoft/botbuilder-samples.git ``` -- Set app settings variables - - - MicrosoftAppType: Type of the App. - - - MicrosoftAppId: App Id of your bot. - - - MicrosoftAppTenantId: Tenant Id to which your bot belongs. - - - KeyVaultName: Name of the KeyVault containing the certificate. - - - CertificateName: Name of the certificate in the KeyVault. - - -- Run the bot from a terminal or from Visual Studio: - - A) From a terminal, navigate to `samples/csharp_dotnetcore/85.bot-authentication-sni` - - ```bash - # run the bot - dotnet run - ``` - - B) Or from Visual Studio - +- Open from Visual Studio - Launch Visual Studio - File -> Open -> Project/Solution - Navigate to `samples/csharp_dotnetcore/85.bot-authentication-sni` folder - Select `AuthSNIBot.csproj` file - - Press `F5` to run the project -## Testing the bot using Bot Framework Emulator +- Create an SSL/TLS certificate using KeyVault + 1. Create a KeyVault resource and assign _the KeyVault Administrator_ role to have permission to create a new certificate. -[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. + 2. Under the Certificates section, hit on Generate/Import, complete the form, and create the certificate in PEM format. -- Install the latest Bot Framework Emulator from [here](https://github.com/Microsoft/BotFramework-Emulator/releases) + 3. Go to the details of the certificate that you created and enable it and record the subject name -### Connect to the bot using Bot Framework Emulator +- Create Azure App and Bot + - Create App Registration + - This can be either Single or Multi tenant + - Record the Application ID + - Add this to the Manifest + "trustedCertificateSubjects": [ + { + "authorityId": "00000000-0000-0000-0000-000000000001", + + "subjectName": "certificate_subject_name", + + "revokedCertificateIdentifiers": [] + } + ] + - Create an Azure Bot in the desired resource group. Use the App Registration from the previous step. -- Launch Bot Framework Emulator -- File -> Open Bot -- Enter a Bot URL of `http://localhost:3978/api/messages` +- Set appsettings.json variables -## Interacting with the bot + - MicrosoftAppType: {SingTenant | MultiTenant} -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. + - MicrosoftAppId: {appId} -## SSL/TLS certificate + - MicrosoftAppTenantId: {tenantId} -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. - -## How to create an SSL/TLS certificate - -There are two possible options to create SSL/TSL certificate. Below is a step-by-step description of each one: - -### Using local environment - -1. Run the following command in a local PowerShell - -``` -$cert = New-SelfSignedCertificate -CertStoreLocation "" -Subject "CN=" -KeySpec KeyExchange -``` - -1. Then, type _Manage User Certificates_ in the Windows search bar and hit enter - -2. The certificate will be located in the _user certificates_ folder, under _personal_ directory. - -3. Export the certificate to _pfx_ format including the key(The default location is _system32_ folder). - -4. Go to the certificate location and run the following command to generate a _pem_ file: - -``` -OpenSSL pkcs12 -in .pfx -out c:\.pem –nodes -``` + - KeyVaultName: Name of the KeyVault containing the certificate. -5. Upload the generated certificate to the Azure app registration. + - CertificateName: Name of the certificate in the KeyVault. -### Using KeyVault +- Run the bot from Visual Studio: -1. Create a KeyVault resource and assign _the KeyVault Administrator_ role to have permission to create a new certificate. +## Interacting with the bot -2. Under the Certificates section, hit on Generate/Import, complete the form, and create the certificate in PEM format. +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. -3. Go to the details of the certificate that you created and enable it. +## SSL/TLS certificate -4. Download the certificate in CER format and then upload it to the Azure app registration. +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. ## Deploy the bot to Azure diff --git a/samples/csharp_dotnetcore/85.bot-authentication-sni/Startup.cs b/samples/csharp_dotnetcore/85.bot-authentication-sni/Startup.cs index 2fdd7d4942..1a183b00ae 100644 --- a/samples/csharp_dotnetcore/85.bot-authentication-sni/Startup.cs +++ b/samples/csharp_dotnetcore/85.bot-authentication-sni/Startup.cs @@ -33,7 +33,15 @@ public void ConfigureServices(IServiceCollection services) options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth; }); - //Set sendX5C value to true to use SNI auhtentication. + + // + // NOTE + // + // This is a provisional sample for SN+I. It is likely to change in the future as this + // functionality is rolled into BF SDK. + // + + // Set sendX5C value to true to use SNI authentication. var sendX5C = true; // Using KeyVault. @@ -43,21 +51,13 @@ public void ConfigureServices(IServiceCollection services) var credential = new DefaultAzureCredential(); var client = new CertificateClient(new Uri(keyVaultUri), credential); - //Get certificate in X509Certificate format. + // Get certificate in X509Certificate format. var certificateName = _configuration["CertificateName"]; var certificate = client.DownloadCertificate(certificateName).Value; - // Using a local certificate. - //var certificate = X509Certificate2.CreateFromPemFile(@"{Pem file path}"); - - // MSAL certificate auth. - services.AddSingleton( - serviceProvider => ConfidentialClientApplicationBuilder.Create(_configuration["MicrosoftAppId"]) - .WithCertificate(certificate, sendX5C) - .Build()); - - // MSAL credential factory: regardless of secret, cert or custom auth, need to add the line below to enable MSAL. - services.AddSingleton(); + // Register CertificateServiceClientCredentialsFactory + services.AddSingleton( + new CertificateServiceClientCredentialsFactory(certificate, _configuration["MicrosoftAppId"], _configuration["MicrosoftAppTenantId"], null, null, sendX5C)); // Create the Bot Framework Authentication to be used with the Bot Adapter. services.AddSingleton(); @@ -65,15 +65,6 @@ public void ConfigureServices(IServiceCollection services) // Create the Bot Adapter with error handling enabled. services.AddSingleton(); - // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.) - services.AddSingleton(); - - // Create the User state. (Used in this bot's Dialog implementation.) - services.AddSingleton(); - - // Create the Conversation state. (Used by the Dialog system itself.) - services.AddSingleton(); - // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. services.AddTransient(); } @@ -93,8 +84,6 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { endpoints.MapControllers(); }); - - // app.UseHttpsRedirection(); } } }