Condividi tramite


Procedura: creare un servizio che utilizza un validator del certificato personalizzato

In questo argomento viene illustrato come implementare un validator del certificato personalizzato e come configurare le credenziali del client o del servizio per sostituire la logica di convalida del certificato predefinita con il validator del certificato personalizzato.

Se il certificato X.509 viene utilizzato per autenticare un client o un servizio, per impostazione predefinita Windows Communication Foundation (WCF) utilizza l'archivio certificati di Windows e l'API di crittografia per convalidare il certificato e verificare che sia attendibile. A volte la funzionalità di convalida del certificato incorporata non è sufficiente e deve essere modificata. WCF fornisce un modo semplice per modificare la logica di convalida consentendo agli utenti di aggiungere un validator del certificato personalizzato. Se si specifica un validator del certificato personalizzato, WCF non utilizza la logica di convalida del certificato incorporata, bensì si basa sul validator personalizzato.

Procedure

Per creare un validator del certificato personalizzato

  1. Definire una nuova classe derivata da X509CertificateValidator.

  2. Implementare il metodo astratto Validate. Il certificato che deve essere convalidato viene passato come argomento al metodo. Se il certificato passato non è valido in base alla logica di convalida, questo metodo genera un'eccezione SecurityTokenValidationException. Se il certificato è valido, il metodo viene restituito al chiamante.

    ms733806.note(it-it,VS.100).gifNota:
    Affinché gli errori di autenticazione vengano restituiti al client, generare una classe FaultException nel metodo 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");
        }
    }
}

Per specificare un validator del certificato personalizzato nella configurazione del servizio

  1. Aggiungere un elemento <behaviors>serviceBehaviors section e una<system.ServiceModel> all'elemento.

  2. Aggiungere un Behavior element e impostare l'attributo name su un valore appropriato.

  3. Aggiungere un <serviceCredentials> Element<behavior> all'elemento .

  4. Aggiungere un elemento <clientCertificate><serviceCredentials> all'elemento .

  5. Aggiungere un <authentication> of <clientCertificate> Element<clientCertificate> all'elemento .

  6. Impostare l'attributo customCertificateValidatorType sul tipo di validator. Nell'esempio seguente viene impostato l'attributo sullo spazio dei nomi e sul nome del tipo.

  7. Impostare l'attributo certificateValidationMode su 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>
    

Per specificare un validator del certificato personalizzato mediante configurazione sul client

  1. Aggiungere un elemento <behaviors>serviceBehaviors section e una<system.ServiceModel> all'elemento.

  2. Aggiungere un elemento <endpointBehaviors>.

  3. Aggiungere un elemento <behavior>name e impostare l'attributo su un valore appropriato.

  4. Aggiungere un elemento <clientCredentials>.

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

  6. Aggiungere un <authentication> of <serviceCertificate> Element come illustrato nell'esempio seguente.

  7. Impostare l'attributo customCertificateValidatorType sul tipo di validator.

  8. Impostare l'attributo certificateValidationMode su Custom. Nell'esempio seguente viene impostato l'attributo sullo spazio dei nomi e sul nome del tipo.

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

Per specificare un validator del certificato personalizzato mediante il codice sul servizio

  1. Specificare il validator del certificato personalizzato sulla proprietà ClientCertificate. È possibile accedere alle credenziali del servizio mediante la proprietà Credentials.

  2. Impostare la proprietà CertificateValidationMode su 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");

Per specificare un validator del certificato personalizzato mediante il codice sul client

  1. Specificare il validator del certificato personalizzato mediante la proprietà CustomCertificateValidator. È possibile accedere alle credenziali del client mediante la proprietà Credentials. (La classe client generata da Strumento ServiceModel Metadata Utility Tool (Svcutil.exe) deriva sempre dalla classe ClientBase.)

  2. Impostare la proprietà CertificateValidationMode su Custom.

Esempio

Descrizione

Nell'esempio seguente viene illustrata un'implementazione di un validator del certificato personalizzato e l'utilizzo sul servizio.

Codice

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");
            }
        }
    }
}

Vedere anche

Riferimento

X509CertificateValidator