Condividi tramite


Procedura: Creare un verificatore di identità client personalizzato

La funzionalità di identità di Windows Communication Foundation (WCF) consente a un client di specificare in anticipo l'identità prevista del servizio. Ogni volta che un server esegue l'autenticazione al client, l'identità viene verificata rispetto all'identità prevista. Per una spiegazione dell'identità e del relativo funzionamento, vedere Identità del servizio e autenticazione.

Se necessario, la verifica può essere personalizzata usando un verificatore di identità personalizzato. Ad esempio, è possibile eseguire controlli aggiuntivi di verifica dell'identità del servizio. In questo esempio, il verificatore di identità personalizzato controlla attestazioni aggiuntive nel certificato X.509 restituito dal server. Per un'applicazione di esempio, vedere Esempio di identità del servizio.

Per estendere la classe EndpointIdentity

  1. Definire una nuova classe che deriva dalla EndpointIdentity classe . In questo esempio viene nominata l'estensione OrgEndpointIdentity.

  2. Aggiungere membri privati insieme alle proprietà che verranno utilizzate dalla classe estesa IdentityVerifier per eseguire il controllo dell'identità rispetto alle attestazioni presenti nel token di sicurezza restituito dal servizio. Questo esempio definisce una proprietà: la OrganizationClaim proprietà .

    public class OrgEndpointIdentity : EndpointIdentity
    {
        private string orgClaim;
        public OrgEndpointIdentity(string orgName)
        {
            orgClaim = orgName;
        }
    
        public string OrganizationClaim
        {
            get { return orgClaim; }
            set { orgClaim = value; }
        }
    }
    
    Public Class OrgEndpointIdentity
        Inherits EndpointIdentity
        Private orgClaim As String
    
        Public Sub New(ByVal orgName As String)
            orgClaim = orgName
        End Sub
    
        Public Property OrganizationClaim() As String
            Get
                Return orgClaim
            End Get
            Set(ByVal value As String)
                orgClaim = value
            End Set
        End Property
    End Class
    

Per estendere la classe IdentityVerifier

  1. Definire una nuova classe che deriva da IdentityVerifier. In questo esempio viene nominata l'estensione CustomIdentityVerifier.

    public class CustomIdentityVerifier : IdentityVerifier
    {
        // Code to be added.
        public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    
        public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
    
    Public Class CustomIdentityVerifier
        Inherits IdentityVerifier
        ' Code to be added.
    
        Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _
                                              ByVal authContext As AuthorizationContext) As Boolean
            Throw New Exception("The method or operation is not implemented.")
        End Function
    
        Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _
                                                 <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean
            Throw New Exception("The method or operation is not implemented.")
        End Function
    End Class
    
  2. Sovrascrivere il metodo CheckAccess. Il metodo determina se il controllo dell'identità ha avuto esito positivo o negativo.

  3. Il CheckAccess metodo ha due parametri. La prima è un'istanza della EndpointIdentity classe . Il secondo è un'istanza della AuthorizationContext classe .

    Nell'implementazione del metodo esaminare la raccolta di attestazioni restituite dalla ClaimSets proprietà della AuthorizationContext classe ed eseguire i controlli di autenticazione in base alle esigenze. Questo esempio inizia trovando qualsiasi attestazione di tipo "Distinguished Name" e quindi confronta il nome con l'estensione di EndpointIdentity (OrgEndpointIdentity).

    public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
    {
        bool returnvalue = false;
    
        foreach (ClaimSet claimset in authContext.ClaimSets)
        {
            foreach (Claim claim in claimset)
            {
                if (claim.ClaimType == "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname")
                {
                    X500DistinguishedName name = (X500DistinguishedName)claim.Resource;
                    if (name.Name.Contains(((OrgEndpointIdentity)identity).OrganizationClaim))
                    {
                        Console.WriteLine($"Claim Type: {claim.ClaimType}");
                        Console.WriteLine($"Right: {claim.Right}");
                        Console.WriteLine($"Resource: {claim.Resource}");
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }
        }
        return returnvalue;
    }
    
    
    Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _
                                          ByVal authContext As AuthorizationContext) As Boolean
    
        Dim returnvalue = False
        For Each claimset In authContext.ClaimSets
            For Each claim In claimset
                If claim.ClaimType = "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname" Then
                    Dim name = CType(claim.Resource, X500DistinguishedName)
                    If name.Name.Contains((CType(identity, OrgEndpointIdentity)).OrganizationClaim) Then
                        Console.WriteLine("Claim Type: {0}", claim.ClaimType)
                        Console.WriteLine("Right: {0}", claim.Right)
                        Console.WriteLine("Resource: {0}", claim.Resource)
                        Console.WriteLine()
                        returnvalue = True
                    End If
                End If
            Next claim
        Next claimset
        Return returnvalue
    
    End Function
    

Per implementare il metodo TryGetIdentity

  1. Implementare il TryGetIdentity metodo , che determina se un'istanza della EndpointIdentity classe può essere restituita dal client. L'infrastruttura WCF chiama prima l'implementazione del metodo TryGetIdentity per recuperare l'identità del servizio a partire dal messaggio. Successivamente, l'infrastruttura chiama l'implementazione CheckAccess con gli oggetti restituiti EndpointIdentity e AuthorizationContext.

  2. TryGetIdentity Nel metodo inserire il codice seguente:

    public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
    {
        return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity);
    }
    
    Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _
                                             <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean
        Return IdentityVerifier.CreateDefault().TryGetIdentity(reference, identity)
    End Function
    
    

Per implementare un binding personalizzato e impostare "IdentityVerifier" personalizzato

  1. Creare un metodo che restituisce un Binding oggetto . Questo esempio inizia a creare un'istanza della WSHttpBinding classe e imposta la relativa modalità di sicurezza su Messagee su ClientCredentialTypeNone.

  2. Creare un oggetto BindingElementCollection utilizzando il metodo CreateBindingElements.

  3. Restituire il SecurityBindingElement dalla raccolta ed effettuare il cast a una variabile SymmetricSecurityBindingElement.

  4. Impostare la IdentityVerifier proprietà della LocalClientSecuritySettings classe su una nuova istanza della CustomIdentityVerifier classe creata in precedenza.

    public static Binding CreateCustomSecurityBinding()
    {
        WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message);
        //Clients are anonymous to the service.
        binding.Security.Message.ClientCredentialType = MessageCredentialType.None;
        //Secure conversation is turned off for simplification. If secure conversation is turned on, then
        //you also need to set the IdentityVerifier on the secureconversation bootstrap binding.
        binding.Security.Message.EstablishSecurityContext = false;
    
        // Get the SecurityBindingElement and cast to a SymmetricSecurityBindingElement to set the IdentityVerifier.
        BindingElementCollection outputBec = binding.CreateBindingElements();
        SymmetricSecurityBindingElement ssbe = (SymmetricSecurityBindingElement)outputBec.Find<SecurityBindingElement>();
    
        //Set the Custom IdentityVerifier.
        ssbe.LocalClientSettings.IdentityVerifier = new CustomIdentityVerifier();
    
        return new CustomBinding(outputBec);
    }
    
    Public Shared Function CreateCustomSecurityBinding() As Binding
        Dim binding As New WSHttpBinding(SecurityMode.Message)
    
        With binding.Security.Message
            'Clients are anonymous to the service.
            .ClientCredentialType = MessageCredentialType.None
            'Secure conversation is turned off for simplification. If secure conversation is turned on, then 
            'you also need to set the IdentityVerifier on the secureconversation bootstrap binding.
            .EstablishSecurityContext = False
        End With
        ' Get the SecurityBindingElement and cast to a SymmetricSecurityBindingElement to set the IdentityVerifier.
        Dim outputBec = binding.CreateBindingElements()
        Dim ssbe = CType(outputBec.Find(Of SecurityBindingElement)(), SymmetricSecurityBindingElement)
    
        'Set the Custom IdentityVerifier.
        ssbe.LocalClientSettings.IdentityVerifier = New CustomIdentityVerifier()
    
        Return New CustomBinding(outputBec)
    End Function
    
  5. Il binding personalizzato restituito viene usato per creare un'istanza sia del client che della classe. Il client può quindi eseguire un controllo di verifica dell'identità personalizzato del servizio, come illustrato nel codice seguente.

    using (CalculatorClient client = new CalculatorClient(customSecurityBinding, serviceAddress))
    {
    
    Using client As New CalculatorClient(customSecurityBinding, serviceAddress)
    

Esempio 1

Nell'esempio seguente viene illustrata un'implementazione completa della IdentityVerifier classe .

class CustomIdentityVerifier : IdentityVerifier
{
    public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
    {
        bool returnvalue = false;

        foreach (ClaimSet claimset in authContext.ClaimSets)
        {
            foreach (Claim claim in claimset)
            {
                if (claim.ClaimType == "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname")
                {
                    X500DistinguishedName name = (X500DistinguishedName)claim.Resource;
                    if (name.Name.Contains(((OrgEndpointIdentity)identity).OrganizationClaim))
                    {
                        Console.WriteLine($"Claim Type: {claim.ClaimType}");
                        Console.WriteLine($"Right: {claim.Right}");
                        Console.WriteLine($"Resource: {claim.Resource}");
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }
        }
        return returnvalue;
    }

    public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
    {
        return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity);
    }
}
Friend Class CustomIdentityVerifier
    Inherits IdentityVerifier

    Public Overrides Function CheckAccess(ByVal identity As EndpointIdentity, _
                                          ByVal authContext As AuthorizationContext) As Boolean

        Dim returnvalue = False
        For Each claimset In authContext.ClaimSets
            For Each claim In claimset
                If claim.ClaimType = "http://schemas.microsoft.com/ws/2005/05/identity/claims/x500distinguishedname" Then
                    Dim name = CType(claim.Resource, X500DistinguishedName)
                    If name.Name.Contains((CType(identity, OrgEndpointIdentity)).OrganizationClaim) Then
                        Console.WriteLine("Claim Type: {0}", claim.ClaimType)
                        Console.WriteLine("Right: {0}", claim.Right)
                        Console.WriteLine("Resource: {0}", claim.Resource)
                        Console.WriteLine()
                        returnvalue = True
                    End If
                End If
            Next claim
        Next claimset
        Return returnvalue

    End Function

    Public Overrides Function TryGetIdentity(ByVal reference As EndpointAddress, _
                                             <System.Runtime.InteropServices.Out()> ByRef identity As EndpointIdentity) As Boolean
        Return IdentityVerifier.CreateDefault().TryGetIdentity(reference, identity)
    End Function

End Class

Esempio 2

Nell'esempio seguente viene illustrata un'implementazione completa della EndpointIdentity classe .

public class OrgEndpointIdentity : EndpointIdentity
{
    private string orgClaim;
    public OrgEndpointIdentity(string orgName)
    {
        orgClaim = orgName;
    }

    public string OrganizationClaim
    {
        get { return orgClaim; }
        set { orgClaim = value; }
    }
}
Public Class OrgEndpointIdentity
    Inherits EndpointIdentity
    Private orgClaim As String

    Public Sub New(ByVal orgName As String)
        orgClaim = orgName
    End Sub

    Public Property OrganizationClaim() As String
        Get
            Return orgClaim
        End Get
        Set(ByVal value As String)
            orgClaim = value
        End Set
    End Property
End Class

Vedere anche