Partager des certificats entre des applications Windows
Les applications Windows qui nécessitent une authentification sécurisée au-delà d’une combinaison d’ID d’utilisateur et de mot de passe peuvent utiliser des certificats pour l’authentification. L’authentification par certificat permet d’authentifier un utilisateur avec un niveau de confiance élevé. Dans certains cas, un groupe de services peut authentifier un utilisateur pour plusieurs applications. Cet article explique comment authentifier plusieurs applications Windows à l’aide du même certificat et comment fournir une méthode permettant aux utilisateurs d’importer un certificat fourni pour accéder aux services web sécurisés.
Les applications peuvent s’authentifier auprès d’un service web à l’aide d’un certificat, et plusieurs applications peuvent utiliser un certificat unique à partir du magasin de certificats pour authentifier le même utilisateur. Si un certificat n’existe pas dans le magasin, vous pouvez ajouter du code à votre application pour importer un certificat à partir d’un fichier PFX. L’application cliente dans ce guide de démarrage rapide est une application WinUI et le service web est une API web ASP.NET Core.
Conseil
Microsoft Copilot est une excellente ressource si vous avez des questions sur la prise en main de l’écriture d’applications Windows ou d’ASP.NET API web Core. Copilot peut vous aider à écrire du code, à trouver des exemples et à en savoir plus sur les meilleures pratiques de création d’applications sécurisées.
Prérequis
- Visual Studio avec les charges de travail de développement ASP.NET et web et de développement d’applications Windows installées.
- Dernier Kit de développement logiciel Windows (SDK) pour utiliser les API Windows Runtime (WinRT) dans votre application WinUI.
- PowerShell pour utiliser des certificats auto-signés.
Créer et publier un service web sécurisé
Ouvrez Microsoft Visual Studio et sélectionnez Créer un projet à partir de l’écran de démarrage.
Dans la boîte de dialogue Créer un projet, sélectionnez l’API dans la liste déroulante Sélectionner un type de projet pour filtrer les modèles de projet disponibles.
Sélectionnez le modèle API web ASP.NET Core, puis Suivant.
Nommez l’application « FirstContosoBank » et sélectionnez Suivant.
Choisissez .NET 8.0 ou version ultérieure en tant que Framework, définissez le type d’authentification sur None, vérifiez que Configurer pour HTTPS est activé, décochez Activer la prise en charge d’OpenAPI, vérifiez Ne pas utiliser d’instructions de niveau supérieur et Utilisez des contrôleurs, puis sélectionnez Créer.
Cliquez avec le bouton droit sur le fichier WeatherForecastController.cs dans le dossier Contrôleurs , puis sélectionnez Renommer. Remplacez le nom par BankController.cs et laissez Visual Studio renommer la classe et toutes les références à la classe.
Dans le fichier launchSettings.json , remplacez la valeur « launchUrl » par « weatherforecast » par « bank » pour les trois configurations qui utilisent la valeur.
Dans le fichier BankController.cs , ajoutez la méthode « Login » suivante.
[HttpGet] [Route("login")] public string Login() { // Return any value you like here. // The client is just looking for a 200 OK response. return "true"; }
Ouvrez le Gestionnaire de package NuGet et recherchez et installez la dernière version stable du package Microsoft.AspNetCore.Authentication.Certificate. Ce package fournit un intergiciel pour l’authentification par certificat dans ASP.NET Core.
Ajoutez une nouvelle classe au projet nommé SecureCertificateValidationService. Ajoutez le code suivant à la classe pour configurer l’intergiciel d’authentification par certificat.
using System.Security.Cryptography.X509Certificates; public class SecureCertificateValidationService { public bool ValidateCertificate(X509Certificate2 clientCertificate) { // Values are hard-coded for this example. // You should load your valid thumbprints from a secure location. string[] allowedThumbprints = { "YOUR_CERTIFICATE_THUMBPRINT_1", "YOUR_CERTIFICATE_THUMBPRINT_2" }; if (allowedThumbprints.Contains(clientCertificate.Thumbprint)) { return true; } } }
Ouvrez Program.cs et remplacez le code dans la méthode Main par le code suivant :
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add our certificate validation service to the DI container. builder.Services.AddTransient<SecureCertificateValidationService>(); builder.Services.Configure<KestrelServerOptions>(options => { // Configure Kestrel to require a client certificate. options.ConfigureHttpsDefaults(options => { options.ClientCertificateMode = ClientCertificateMode.RequireCertificate; options.AllowAnyClientCertificate(); }); }); builder.Services.AddControllers(); // Add certificate authentication middleware. builder.Services.AddAuthentication( CertificateAuthenticationDefaults.AuthenticationScheme) .AddCertificate(options => { options.AllowedCertificateTypes = CertificateTypes.SelfSigned; options.Events = new CertificateAuthenticationEvents { // Validate the certificate with the validation service. OnCertificateValidated = context => { var validationService = context.HttpContext.RequestServices.GetService<SecureCertificateValidationService>(); if (validationService.ValidateCertificate(context.ClientCertificate)) { context.Success(); } else { context.Fail("Invalid certificate"); } return Task.CompletedTask; }, OnAuthenticationFailed = context => { context.Fail("Invalid certificate"); return Task.CompletedTask; } }; }); var app = builder.Build(); // Add authentication/authorization middleware. app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run(); }
Le code ci-dessus configure le serveur Kestrel pour exiger un certificat client et ajoute l’intergiciel d’authentification de certificat à l’application. L’intergiciel valide le certificat client à l’aide de la
SecureCertificateValidationService
classe. L’événementOnCertificateValidated
est appelé lorsqu’un certificat est validé. Si le certificat est valide, l’événement appelle laSuccess
méthode. Si le certificat n’est pas valide, l’événement appelle laFail
méthode avec un message d’erreur, qui sera retourné au client.Démarrez le débogage du projet pour lancer le service web. Vous pouvez recevoir des messages sur l’approbation et l’installation d’un certificat SSL. Cliquez sur Oui pour chacun de ces messages pour approuver le certificat et continuer le débogage du projet.
Le service web sera disponible à l’adresse
https://localhost:7072/bank
. Vous pouvez tester le service web en ouvrant un navigateur web et en entrant l’adresse web. Vous verrez les données de prévision météorologique générées au format JSON. Conservez le service web en cours d’exécution pendant la création de l’application cliente.
Pour plus d’informations sur l’utilisation d’API web basées sur ASP.NET contrôleur core, consultez Créer une API web avec ASP.NET Core.
Créer une application WinUI qui utilise l’authentification par certificat
Maintenant que vous disposez d’un ou plusieurs services web sécurisés, vos applications peuvent utiliser des certificats pour s’authentifier auprès de ces services web. Lorsque vous effectuez une demande à un service web authentifié à l’aide de l’objet HttpClient à partir des API WinRT, la requête initiale ne contient pas de certificat client. Le service web authentifié répond avec une demande d’authentification du client. Lorsque cela se produit, le client Windows interroge automatiquement le magasin de certificats pour les certificats clients disponibles. Votre utilisateur peut sélectionner parmi ces certificats pour s’authentifier auprès du service web. Certains certificats sont protégés par mot de passe. Vous devez donc fournir à l’utilisateur un moyen d’entrer le mot de passe d’un certificat.
Remarque
Il n’existe pas encore d’API du Kit de développement logiciel (SDK) d’application Windows pour gérer les certificats. Vous devez utiliser les API WinRT pour gérer les certificats dans votre application. Nous allons également utiliser des API de stockage WinRT pour importer un certificat à partir d’un fichier PFX. De nombreuses API WinRT peuvent être utilisées par n’importe quelle application Windows avec une identité de package, y compris les applications WinUI.
Le code client HTTP que nous allons implémenter utilise . HttpClient de NET. HttpClient inclus dans les API WinRT ne prend pas en charge les certificats clients.
S’il n’existe aucun certificat client disponible, l’utilisateur doit ajouter un certificat au magasin de certificats. Vous pouvez inclure du code dans votre application qui permet à un utilisateur de sélectionner un fichier PFX qui contient un certificat client, puis d’importer ce certificat dans le magasin de certificats client.
Conseil
Vous pouvez utiliser les applets de commande PowerShell New-SelfSignedCertificate et Export-PfxCertificate pour créer un certificat auto-signé et l’exporter vers un fichier PFX à utiliser avec ce guide de démarrage rapide. Pour plus d’informations, consultez New-SelfSignedCertificate et Export-PfxCertificate.
Notez que lors de la génération du certificat, vous devez enregistrer l’empreinte numérique du certificat à utiliser dans le service web pour la validation.
Ouvrez Visual Studio et créez un projet WinUI à partir de la page de démarrage. Nommez le nouveau projet « FirstContosoBankApp ». Cliquez sur Créer pour créer le projet.
Dans le fichier MainWindow.xaml, ajoutez le code XAML suivant à un élément Grid, en remplaçant l’élément StackPanel existant et son contenu. Ce code XAML inclut un bouton permettant de rechercher un fichier PFX à importer, une zone de texte pour entrer un mot de passe pour un fichier PFX protégé par mot de passe, un bouton permettant d’importer un fichier PFX sélectionné, un bouton permettant de se connecter au service web sécurisé et un bloc de texte pour afficher l’état de l’action actuelle.
<Button x:Name="Import" Content="Import Certificate (PFX file)" HorizontalAlignment="Left" Margin="352,305,0,0" VerticalAlignment="Top" Height="77" Width="260" Click="Import_Click" FontSize="16"/> <Button x:Name="Login" Content="Login" HorizontalAlignment="Left" Margin="611,305,0,0" VerticalAlignment="Top" Height="75" Width="240" Click="Login_Click" FontSize="16"/> <TextBlock x:Name="Result" HorizontalAlignment="Left" Margin="355,398,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="153" Width="560"/> <PasswordBox x:Name="PfxPassword" HorizontalAlignment="Left" Margin="483,271,0,0" VerticalAlignment="Top" Width="229"/> <TextBlock HorizontalAlignment="Left" Margin="355,271,0,0" TextWrapping="Wrap" Text="PFX password" VerticalAlignment="Top" FontSize="18" Height="32" Width="123"/> <Button x:Name="Browse" Content="Browse for PFX file" HorizontalAlignment="Left" Margin="352,189,0,0" VerticalAlignment="Top" Click="Browse_Click" Width="499" Height="68" FontSize="16"/> <TextBlock HorizontalAlignment="Left" Margin="717,271,0,0" TextWrapping="Wrap" Text="(Optional)" VerticalAlignment="Top" Height="32" Width="83" FontSize="16"/>
Enregistrez les modifications de MainWindow .
Ouvrez le fichier MainWindow.xaml.cs et ajoutez les instructions suivantes
using
.using System; using System.Security.Cryptography.X509Certificates; using System.Diagnostics; using System.Net.Http; using System.Net; using System.Text; using Microsoft.UI.Xaml; using Windows.Security.Cryptography.Certificates; using Windows.Storage.Pickers; using Windows.Storage; using Windows.Storage.Streams;
Dans le fichier MainWindow.xaml.cs, ajoutez les variables suivantes à la classe MainWindow . Ils spécifient l’adresse du point de terminaison de service de connexion sécurisé de votre service web « FirstContosoBank » et une variable globale qui contient un certificat PFX à importer dans le magasin de certificats. Mettez à
localhost:7072
jour le<server-name>
port vers ou le port spécifié dans la configuration « https » dans le fichier launchSettings.json de votre projet d’API.private Uri requestUri = new Uri("https://<server-name>/bank/login"); private string pfxCert = null;
Dans le fichier MainWindow.xaml.cs , ajoutez le gestionnaire de clics suivant pour le bouton de connexion et la méthode permettant d’accéder au service web sécurisé.
private void Login_Click(object sender, RoutedEventArgs e) { MakeHttpsCall(); } private async void MakeHttpsCall() { var result = new StringBuilder("Login "); // Load the certificate var certificate = new X509Certificate2(Convert.FromBase64String(pfxCert), PfxPassword.Password); // Create HttpClientHandler and add the certificate var handler = new HttpClientHandler(); handler.ClientCertificates.Add(certificate); handler.ClientCertificateOptions = ClientCertificateOption.Automatic; // Create HttpClient with the handler var client = new HttpClient(handler); try { // Make a request var response = await client.GetAsync(requestUri); if (response.StatusCode == HttpStatusCode.OK) { result.Append("successful"); } else { result = result.Append("failed with "); result = result.Append(response.StatusCode); } } catch (Exception ex) { result = result.Append("failed with "); result = result.Append(ex.Message); } Result.Text = result.ToString(); }
Ensuite, ajoutez les gestionnaires de clics suivants pour le bouton pour rechercher un fichier PFX et le bouton pour importer un fichier PFX sélectionné dans le magasin de certificats.
private async void Import_Click(object sender, RoutedEventArgs e) { try { Result.Text = "Importing selected certificate into user certificate store...."; await CertificateEnrollmentManager.UserCertificateEnrollmentManager.ImportPfxDataAsync( pfxCert, PfxPassword.Password, ExportOption.Exportable, KeyProtectionLevel.NoConsent, InstallOptions.DeleteExpired, "Import Pfx"); Result.Text = "Certificate import succeeded"; } catch (Exception ex) { Result.Text = "Certificate import failed with " + ex.Message; } } private async void Browse_Click(object sender, RoutedEventArgs e) { var result = new StringBuilder("Pfx file selection "); var pfxFilePicker = new FileOpenPicker(); IntPtr hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this); WinRT.Interop.InitializeWithWindow.Initialize(pfxFilePicker, hwnd); pfxFilePicker.FileTypeFilter.Add(".pfx"); pfxFilePicker.CommitButtonText = "Open"; try { StorageFile pfxFile = await pfxFilePicker.PickSingleFileAsync(); if (pfxFile != null) { IBuffer buffer = await FileIO.ReadBufferAsync(pfxFile); using (DataReader dataReader = DataReader.FromBuffer(buffer)) { byte[] bytes = new byte[buffer.Length]; dataReader.ReadBytes(bytes); pfxCert = System.Convert.ToBase64String(bytes); PfxPassword.Password = string.Empty; result.Append("succeeded"); } } else { result.Append("failed"); } } catch (Exception ex) { result.Append("failed with "); result.Append(ex.Message); ; } Result.Text = result.ToString(); }
Ouvrez le fichier Package.appxmanifest et ajoutez les fonctionnalités suivantes à l’onglet Fonctionnalités .
- EnterpriseAuthentication
- SharedUserCertificates
Exécutez votre application et connectez-vous à votre service web sécurisé, ainsi que l’importation d’un fichier PFX dans le magasin de certificats local.
Vous pouvez utiliser ces étapes pour créer plusieurs applications qui utilisent le même certificat d’utilisateur pour accéder au même ou à différents services web sécurisés.
Contenu connexe
Windows developer