Partager via


Comment : créer un service qui utilise un validateur de certificat personnalisé

Cette rubrique décrit comment implémenter un validateur de certificat personnalisé et comment configurer les informations d'identification du service ou du client pour remplacer la logique de validation de certificat par défaut par le validateur de certificat personnalisé.

Si le certificat X.509 est utilisé pour authentifier un client ou un service, Windows Communication Foundation (WCF) utilise par défaut le magasin de certificats Windows et API Crypto pour valider le certificat et garantir qu'il est approuvé. Les fonctionnalités intégrées de validation du certificat sont parfois insuffisantes et doivent être changées. WCF offre un moyen facile pour modifier la logique de validation en permettant aux utilisateurs d'ajouter un validateur de certificat personnalisé. Si un validateur de certificat personnalisé est spécifié, WCF n'utilise pas la logique intégrée de validation de certificat mais fait appel au validateur personnalisé.

Procédures

Pour créer un validateur de certificat personnalisé

  1. Définissez une nouvelle classe dérivée de X509CertificateValidator.

  2. Implémentez la méthode abstraite Validate. Le certificat qui doit être validé est passé sous la forme d'un argument à la méthode. Si le certificat passé n'est pas valide selon la logique de validation, cette méthode lève une SecurityTokenValidationException. Si le certificat est valide, la méthode est retournée à l'appelant.

    ms733806.note(fr-fr,VS.100).gifRemarque :
    Pour renvoyer des erreurs d'authentification au client, levez une exception FaultException dans la méthode Validate.

Public Class MyX509CertificateValidator
    Inherits X509CertificateValidator
    Private allowedIssuerName As String
    
    Public Sub New(ByVal allowedIssuerName As String) 
        If allowedIssuerName Is Nothing Then
            Throw New ArgumentNullException("allowedIssuerName")
        End If
        
        Me.allowedIssuerName = allowedIssuerName
    
    End Sub 
        
    Public Overrides Sub Validate(ByVal certificate As X509Certificate2) 
        ' Check that there is a certificate.
        If certificate Is Nothing Then
            Throw New ArgumentNullException("certificate")
        End If
        
        ' Check that the certificate issuer matches the configured issuer.
        If allowedIssuerName <> certificate.IssuerName.Name Then
            Throw New SecurityTokenValidationException _
              ("Certificate was not issued by a trusted issuer")
        End If
    
    End Sub 
End Class 
public class MyX509CertificateValidator : X509CertificateValidator
{
    string allowedIssuerName;

    public MyX509CertificateValidator(string allowedIssuerName)
    {
        if (allowedIssuerName == null)
        {
            throw new ArgumentNullException("allowedIssuerName");
        }

        this.allowedIssuerName = allowedIssuerName;
    }

    public override void Validate(X509Certificate2 certificate)
    {
        // Check that there is a certificate.
        if (certificate == null)
        {
            throw new ArgumentNullException("certificate");
        }

        // Check that the certificate issuer matches the configured issuer.
        if (allowedIssuerName != certificate.IssuerName.Name)
        {
            throw new SecurityTokenValidationException
              ("Certificate was not issued by a trusted issuer");
        }
    }
}

Pour spécifier un validateur de certificat personnalisé dans la configuration du service

  1. Ajoutez un élément <behaviors> et serviceBehaviors section à l'élément <system.ServiceModel>.

  2. Ajoutez un Behavior element et affectez une valeur appropriée à l'attribut name.

  3. Ajoutez un <serviceCredentials> Element à l'élément <behavior>.

  4. Ajoutez un élément <clientCertificate> à l'élément <serviceCredentials>.

  5. Ajoutez un <authentication> of <clientCertificate> Element à l'élément <clientCertificate>.

  6. Affectez à l'attribut customCertificateValidatorType le type de validateur. L'exemple suivant affecte à l'attribut l'espace de noms et le nom du type.

  7. Affectez à l'attribut certificateValidationMode la valeur Custom.

    <configuration>
     <system.serviceModel>
      <behaviors>
       <serviceBehaviors>
        <behavior name="ServiceBehavior">
         <serviceCredentials>
          <clientCertificate>
          <authentication certificateValidationMode="Custom" customCertificateValidatorType="Samples.MyValidator, service" />
          </clientCertificate>
         </serviceCredentials>
        </behavior>
       </serviceBehaviors>
      </behaviors>
    </system.serviceModel>
    </configuration>
    

Pour spécifier un validateur de certificat personnalisé à l'aide de la configuration sur le client

  1. Ajoutez un élément <behaviors> et serviceBehaviors section à l'élément <system.ServiceModel>.

  2. Ajoutez un élément <endpointBehaviors>.

  3. Ajoutez un élément <behavior>, puis affectez à l'attribut name une valeur appropriée.

  4. Ajoutez un élément <clientCredentials>.

  5. Ajoutez un <serviceCertificate> of <clientCredentials> Element

  6. Ajoutez un <authentication> of <serviceCertificate> Element comme illustré dans l'exemple suivant.

  7. Affectez à l'attribut customCertificateValidatorType le type de validateur.

  8. Affectez à l'attribut certificateValidationMode la valeur Custom. L'exemple suivant affecte à l'attribut l'espace de noms et le nom du type.

    <configuration>
     <system.serviceModel>
      <behaviors>
       <endpointBehaviors>
        <behavior name="clientBehavior">
         <clientCredentials>
          <serviceCertificate>
           <authentication certificateValidationMode="Custom" 
                  customCertificateValidatorType=
             "Samples.CustomX509CertificateValidator, client"/>
          </serviceCertificate>
         </clientCredentials>
        </behavior>
       </endpointBehaviors>
      </behaviors>
     </system.serviceModel>
    </configuration>
    

Pour spécifier un validateur de certificat personnalisé à l'aide du code sur le service

  1. Spécifiez le validateur de certificat personnalisé sur la propriété ClientCertificate. Vous pouvez accéder aux informations d'identification de service à l'aide de la propriété Credentials.

  2. Affectez la valeur Custom à la propriété CertificateValidationMode.

serviceHost.Credentials.ClientCertificate.Authentication. _
    CertificateValidationMode = X509CertificateValidationMode.Custom
serviceHost.Credentials.ClientCertificate.Authentication. _
   CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = 
    X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
    new MyX509CertificateValidator("CN=Contoso.com");

Pour spécifier un validateur de certificat personnalisé à l'aide du code sur le client

  1. Spécifiez le validateur de certificat personnalisé à l'aide de la propriété CustomCertificateValidator. Vous pouvez accéder aux informations d'identification du client à l'aide de la propriété Credentials. (La classe de client générée par Outil Service Model Metadata Tool (Svcutil.exe) dérive toujours de la classe ClientBase.)

  2. Affectez la valeur Custom à la propriété CertificateValidationMode.

Exemple

Description

L'exemple suivant montre une implémentation d'un validateur de certificat personnalisé et son utilisation sur le service.

Code

Imports System
Imports System.IdentityModel.Selectors
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Security
Imports System.IdentityModel.Tokens
Imports System.Security.Permissions

<assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution := True)>
<ServiceContract([Namespace] := "http://Microsoft.ServiceModel.Samples")>  _
Public Interface ICalculator
    <OperationContract()>  _
    Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double 
End Interface 


Public Class CalculatorService
    Implements ICalculator
    
    Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double _
       Implements ICalculator.Add
        Dim result As Double = n1 + n2
        Return result    
    End Function 
End Class 


Class Program
    
    Shared Sub Main() 
        Dim serviceHost As New ServiceHost(GetType(CalculatorService))
        Try
            serviceHost.Credentials.ClientCertificate.Authentication. _
                CertificateValidationMode = X509CertificateValidationMode.Custom
            serviceHost.Credentials.ClientCertificate.Authentication. _
               CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
            serviceHost.Open()
            Console.WriteLine("Service started, press ENTER to stop ...")
            Console.ReadLine()
            
            serviceHost.Close()
        Finally
            serviceHost.Close()
        End Try
    
    End Sub 
End Class 

Public Class MyX509CertificateValidator
    Inherits X509CertificateValidator
    Private allowedIssuerName As String
    
    Public Sub New(ByVal allowedIssuerName As String) 
        If allowedIssuerName Is Nothing Then
            Throw New ArgumentNullException("allowedIssuerName")
        End If
        
        Me.allowedIssuerName = allowedIssuerName
    
    End Sub 
        
    Public Overrides Sub Validate(ByVal certificate As X509Certificate2) 
        ' Check that there is a certificate.
        If certificate Is Nothing Then
            Throw New ArgumentNullException("certificate")
        End If
        
        ' Check that the certificate issuer matches the configured issuer.
        If allowedIssuerName <> certificate.IssuerName.Name Then
            Throw New SecurityTokenValidationException _
              ("Certificate was not issued by a trusted issuer")
        End If
    
    End Sub 
End Class 
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;

using System.Security.Permissions;

[assembly: SecurityPermission(
   SecurityAction.RequestMinimum, Execution = true)]
namespace Microsoft.ServiceModel.Samples
{ 
    [ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator
    {
        [OperationContract]
        double Add(double n1, double n2);
    }

    public class CalculatorService : ICalculator
    {
        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }
    }

    class Program
    {
        static void Main()
        {
            using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
            {
                serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = 
                    X509CertificateValidationMode.Custom;
                serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator = 
                    new MyX509CertificateValidator("CN=Contoso.com");

                serviceHost.Open();
                Console.WriteLine("Service started, press ENTER to stop ...");
                Console.ReadLine();

                serviceHost.Close();
            }
        }
    }

    public class MyX509CertificateValidator : X509CertificateValidator
    {
        string allowedIssuerName;

        public MyX509CertificateValidator(string allowedIssuerName)
        {
            if (allowedIssuerName == null)
            {
                throw new ArgumentNullException("allowedIssuerName");
            }

            this.allowedIssuerName = allowedIssuerName;
        }

        public override void Validate(X509Certificate2 certificate)
        {
            // Check that there is a certificate.
            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }

            // Check that the certificate issuer matches the configured issuer.
            if (allowedIssuerName != certificate.IssuerName.Name)
            {
                throw new SecurityTokenValidationException
                  ("Certificate was not issued by a trusted issuer");
            }
        }
    }
}

Voir aussi

Référence

X509CertificateValidator