Delen via


Hoe een aangepaste clientidentiteitsverificator te maken

Met de identiteit functie van Windows Communication Foundation (WCF) kan een client vooraf de verwachte identiteit van de service opgeven. Wanneer een server zichzelf verifieert bij de client, wordt de identiteit gecontroleerd op basis van de verwachte identiteit. (Zie Service Identity and Authenticationvoor een uitleg van identiteit en hoe deze werkt.)

Indien nodig kan de verificatie worden aangepast met behulp van een aangepaste identiteitsverificator. U kunt bijvoorbeeld aanvullende verificatiecontroles voor service-identiteiten uitvoeren. In dit voorbeeld controleert de aangepaste identiteitscontrole aanvullende claims in het X.509-certificaat dat is geretourneerd door de server. Zie Service Identity Samplevoor een voorbeeldtoepassing.

De EndpointIdentity-klasse uitbreiden

  1. Definieer een nieuwe klasse die is afgeleid van de EndpointIdentity-klasse. In dit voorbeeld wordt de extensie OrgEndpointIdentitygenoemd.

  2. Voeg privéleden toe, samen met eigenschappen die worden gebruikt door de uitgebreide IdentityVerifier-klasse om de identiteitscontrole uit te voeren op claims in het beveiligingstoken dat door de service wordt geretourneerd. In dit voorbeeld wordt één eigenschap gedefinieerd: de eigenschap OrganizationClaim.

    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
    

De IdentityVerifier-klasse uitbreiden

  1. Definieer een nieuwe klasse die is afgeleid van IdentityVerifier. In dit voorbeeld wordt de extensie CustomIdentityVerifiergenoemd.

    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. Overschrijf de methode CheckAccess. De methode bepaalt of de identiteitscontrole is geslaagd of mislukt.

  3. De methode CheckAccess heeft twee parameters. De eerste is een exemplaar van de klasse EndpointIdentity. De tweede is een exemplaar van de klasse AuthorizationContext.

    Bekijk in de methode-implementatie de verzameling claims die worden geretourneerd door de eigenschap ClaimSets van de AuthorizationContext-klasse en voer waar nodig verificatiecontroles uit. Dit voorbeeld begint met het vinden van een claim van het type 'DN-naam' en vergelijkt vervolgens de naam met de extensie van de 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
    

De TryGetIdentity-methode implementeren

  1. Implementeer de TryGetIdentity methode, waarmee wordt bepaald of een exemplaar van de EndpointIdentity-klasse door de client kan worden geretourneerd. De WCF-infrastructuur roept de implementatie van de TryGetIdentity methode eerst aan om de identiteit van de service op te halen uit het bericht. Vervolgens roept de infrastructuur de CheckAccess-implementatie aan met de geretourneerde EndpointIdentity en AuthorizationContext.

  2. Plaats in de methode TryGetIdentity de volgende code:

    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
    
    

Een aangepaste binding implementeren en de aangepaste IdentityVerifier instellen

  1. Maak een methode die een Binding-object retourneert. In dit voorbeeld wordt een exemplaar van de WSHttpBinding-klasse gemaakt en wordt de beveiligingsmodus ingesteld op Messageen de bijbehorende ClientCredentialType op None.

  2. Maak een BindingElementCollection met behulp van de methode CreateBindingElements.

  3. Retourneer de SecurityBindingElement uit de verzameling en cast deze naar een SymmetricSecurityBindingElement variabele.

  4. Stel de eigenschap IdentityVerifier van de LocalClientSecuritySettings-klasse in op een nieuw exemplaar van de CustomIdentityVerifier-klasse die u eerder hebt gemaakt.

    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. De aangepaste binding die wordt geretourneerd, wordt gebruikt om een exemplaar van de client en klasse te maken. De client kan vervolgens een aangepaste identiteitsverificatie van de service uitvoeren, zoals wordt weergegeven in de volgende code.

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

Voorbeeld 1

In het volgende voorbeeld ziet u een volledige implementatie van de klasse IdentityVerifier.

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

Voorbeeld 2

In het volgende voorbeeld ziet u een volledige implementatie van de klasse EndpointIdentity.

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

Zie ook