Procédure : 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 simple 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é
Définissez une nouvelle classe dérivée de X509CertificateValidator.
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.
Notes
Pour renvoyer des erreurs d'authentification au client, levez une exception FaultException dans la méthode Validate.
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");
}
}
}
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
Pour spécifier un validateur de certificat personnalisé dans la configuration du service
Ajoutez un élément <comportement> et des <serviceBehaviors> à l’élément <system.serviceModel>.
Ajoutez un élément <behavior>, puis affectez à l’attribut
name
une valeur appropriée.Ajoutez des <serviceCredentials> à l’élément
<behavior>
.Ajoutez un élément
<clientCertificate>
à l'élément<serviceCredentials>
.Ajoutez une <authentication> à l’élément
<clientCertificate>
.Affectez à l'attribut
customCertificateValidatorType
le type de validateur. L'exemple suivant affecte à l'attribut l'espace de noms et le nom du type.Affectez à l'attribut
certificateValidationMode
la valeurCustom
.<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
Ajoutez un élément <comportement> et des <serviceBehaviors> à l’élément <system.serviceModel>.
Ajoutez un élément <endpointBehaviors>.
Ajoutez un élément
<behavior>
, puis affectez à l'attributname
une valeur appropriée.Ajoutez un élément <clientCredentials>.
Ajoutez un <serviceCertificate>.
Ajoutez une <authentification>, comme indiqué dans l’exemple suivant.
Affectez à l'attribut
customCertificateValidatorType
le type de validateur.Affectez à l'attribut
certificateValidationMode
la valeurCustom
. 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
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.
Définissez la propriété CertificateValidationMode sur Custom.
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
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 cliente générée par l’Outil Service Model Metadata Tool (Svcutil.exe) dérive toujours de la classe ClientBase<TChannel>.)
Définissez la propriété CertificateValidationMode sur Custom.
Exemple
Description
L'exemple suivant montre une implémentation d'un validateur de certificat personnalisé et son utilisation sur le service.
Code
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;
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");
}
}
}
}
Imports System.IdentityModel.Selectors
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Security
Imports System.IdentityModel.Tokens
Imports System.Security.Permissions
<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