Compartir a través de


Cómo crear un comprobador de identidad de cliente personalizado

La característica de identidad de Windows Communication Foundation (WCF) permite a un cliente especificar de antemano la identidad deseada para el servicio. Siempre que un servidor se autentica al cliente, se comprueba la identidad frente a la identidad prevista. (Para obtener información acerca de la identidad y su funcionamiento, vea Identidad del servicio y autenticación.)

En caso necesario, la comprobación puede personalizarse mediante un comprobador de identidad personalizado. Por ejemplo, puede realizar controles adicionales de comprobación de identidad del servicio. En este ejemplo, el comprobador de identidad personalizado controla las notificaciones adicionales del certificado X.509 devueltas desde el servidor. Para obtener una aplicación de ejemplo, consulte Ejemplo de identidad de servicio.

Para extender la clase EndpointIdentity

  1. Defina una nueva clase derivada de la clase EndpointIdentity. Este ejemplo asigna nombre a la OrgEndpointIdentity de la extensión

  2. Agregue los miembros privados y las propiedades que utilizará la clase IdentityVerifier extendida para realizar la comprobación de identidad frente a las notificaciones del token de seguridad devueltas por el servicio. Este ejemplo define una propiedad: OrganizationClaim.

    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
    
    public class OrgEndpointIdentity : EndpointIdentity
    {
        private string orgClaim;
        public OrgEndpointIdentity(string orgName)
        {
            orgClaim = orgName;
        }
    
        public string OrganizationClaim
        {
            get { return orgClaim; }
            set { orgClaim = value; }
        }
    }
    

Para extender la clase IdentityVerifier

  1. Defina una nueva clase derivada de IdentityVerifier. Este ejemplo asigna nombre a la CustomIdentityVerifier de la extensión

    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
    
    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.");
        }
    }
    
  2. Invalide el método CheckAccess. El método determina si la comprobación de la identidad tuvo éxito o fue fallida.

  3. El método CheckAccess posee dos parámetros. El primero es una instancia de la clase EndpointIdentity. El segundo es una instancia de la clase AuthorizationContext.

    En la implementación del método, examine la colección de notificaciones devuelta por la propiedad ClaimSets de la clase AuthorizationContext, y realice las comprobaciones de autenticación necesarias. Este ejemplo comienza buscando cualquier notificación de tipo "Nombre distintivo" y, a continuación, compara el nombre con la extensión de EndpointIdentity (OrgEndpointIdentity).

    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 = "https://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 override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
    {
        bool returnvalue = false;
    
        foreach (ClaimSet claimset in authContext.ClaimSets)
        {
            foreach (Claim claim in claimset)
            {
                if (claim.ClaimType == "https://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: {0}", claim.ClaimType);
                        Console.WriteLine("Right: {0}", claim.Right);
                        Console.WriteLine("Resource: {0}", claim.Resource);
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }
    
        }
        return returnvalue;
    }
    

Para implementar el método TryGetIdentity

  1. Implemente el método TryGetIdentity, que determina si el cliente puede devolver una instancia de la clase EndpointIdentity. La infraestructura WCF llama primero a la implementación del método TryGetIdentity para recuperar la identidad del servicio desde el mensaje. Después, la infraestructura llama a la implementación CheckAccess con la EndpointIdentity devuelta y a AuthorizationContext.

  2. En el método TryGetIdentity, agregue el siguiente código:

    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
    
    public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
    {
        return IdentityVerifier.CreateDefault().TryGetIdentity(reference, out identity);
    }
    

Para implementar un enlace personalizado y establecer el método IdentityVerifier personalizado

  1. Cree un método que devuelva un objeto Binding. Este ejemplo comienza creando una instancia de la clase WSHttpBinding y estableciendo su modo de seguridad en Message, y su ClientCredentialType en None.

  2. Cree una BindingElementCollection mediante el método CreateBindingElements.

  3. Recupere el SecurityBindingElement de la colección y conviértalo a una variable SymmetricSecurityBindingElement.

  4. Establezca la propiedad IdentityVerifier de la clase LocalClientSecuritySettings a una nueva instancia de la clase CustomIdentityVerifier creada anteriormente.

    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
    
    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);
    }
    
  5. El enlace personalizado devuelto se utiliza para crear una instancia del cliente y la clase. El cliente puede realizar un control de comprobación de identidad personalizada del servicio, como muestra el código siguiente.

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

Ejemplo

En el siguiente ejemplo se muestra una implementación de la clase IdentityVerifier completa.

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 = "https://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
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 == "https://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: {0}", claim.ClaimType);
                        Console.WriteLine("Right: {0}", claim.Right);
                        Console.WriteLine("Resource: {0}", claim.Resource);
                        Console.WriteLine();
                        returnvalue = true;
                    }
                }
            }

        }
        return returnvalue;
    }

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

En el siguiente ejemplo se muestra una implementación de la clase EndpointIdentity completa.

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
public class OrgEndpointIdentity : EndpointIdentity
{
    private string orgClaim;
    public OrgEndpointIdentity(string orgName)
    {
        orgClaim = orgName;
    }

    public string OrganizationClaim
    {
        get { return orgClaim; }
        set { orgClaim = value; }
    }
}

Vea también

Tareas

Ejemplo de identidad de servicio
Directiva de autorización
Directiva de autorización

Referencia

ServiceAuthorizationManager
EndpointIdentity
IdentityVerifier