Partager via


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

Créer et publier un service web sécurisé

  1. Ouvrez Microsoft Visual Studio et sélectionnez Créer un projet à partir de l’écran de démarrage.

  2. 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.

  3. Sélectionnez le modèle API web ASP.NET Core, puis Suivant.

  4. Nommez l’application « FirstContosoBank » et sélectionnez Suivant.

  5. 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.

    Capture d’écran de Visual Studio create new project details for the ASP.NET Core web API project

  6. 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.

  7. Dans le fichier launchSettings.json , remplacez la valeur « launchUrl » par « weatherforecast » par « bank » pour les trois configurations qui utilisent la valeur.

  8. 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";
    }
    
  9. 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.

  10. 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;
            }
        }
    }
    
  11. 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énement OnCertificateValidated est appelé lorsqu’un certificat est validé. Si le certificat est valide, l’événement appelle la Success méthode. Si le certificat n’est pas valide, l’événement appelle la Fail méthode avec un message d’erreur, qui sera retourné au client.

  12. 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.

    Capture d’écran d’une boîte de dialogue demandant à l’utilisateur s’il souhaite approuver un certificat

    Capture d’écran d’une boîte de dialogue Windows demandant à l’utilisateur s’il souhaite installer un certificat

  13. 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.

  1. 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.

  2. 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"/>
    
  3. Enregistrez les modifications de MainWindow .

  4. 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;
    
  5. 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;
    
  6. 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();
    }
    
  7. 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();
    }
    
  8. Ouvrez le fichier Package.appxmanifest et ajoutez les fonctionnalités suivantes à l’onglet Fonctionnalités .

    • EnterpriseAuthentication
    • SharedUserCertificates
  9. 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.

    Capture d’écran de l’application WinUI avec des boutons permettant de rechercher un fichier PFX, d’importer un certificat et de vous connecter à un service web sécurisé

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.

Windows Hello

Sécurité et identité

Créer une API web avec ASP.NET Core