Tutorial: Crear credenciales de cliente y servicio personalizadas
En este tema se muestra cómo implementar credenciales de cliente y servicio personalizadas y cómo utilizar las credenciales personalizadas desde el código de la aplicación.
Clases de extensibilidad de credenciales
Las clases ClientCredentials y ServiceCredentials son los puntos de entrada principales a la extensibilidad de la seguridad de Windows Communication Foundation (WCF). Estas clases de credenciales proporcionan las API que permiten al código de la aplicación establecer información de las credenciales y convertir los tipos de credenciales en tokens de seguridad. (Los tokens de seguridad son la forma que se usa para transmitir información de credenciales dentro de los mensajes SOAP). Las responsabilidades de estas clases de credenciales pueden dividirse en dos áreas:
Proporcione las API para que las aplicaciones establezcan la información de las credenciales.
Haga las funciones de un generador para las implementaciones de SecurityTokenManager.
Las implementaciones predeterminadas proporcionadas en WCF admiten los tipos de credenciales proporcionados por el sistema y crean un administrador de tokens de seguridad que es capaz de administrar esos tipos de credenciales.
Razones para personalizar
Hay varias razones para personalizar las clases de credenciales de cliente o servicio. En primer lugar está el requisito de cambiar el comportamiento de seguridad predeterminado de WCF con respecto a la administración de los tipos de credenciales proporcionados por el sistema, sobre todo por las razones siguientes:
Cambios que no son posibles mediante otros puntos de extensibilidad.
Agregar nuevos tipos de credenciales.
Agregar nuevos tipos de tokens de seguridad personalizados.
En este tema se describe cómo implementar credenciales de cliente y servicio personalizadas y cómo utilizarlas desde el código de la aplicación.
Primero en una serie
Crear una clase de credenciales personalizadas sólo es el primer paso, porque la razón para personalizar las credenciales es cambiar el comportamiento de WCF con respecto al suministro de credenciales, serialización de tokens de seguridad o autenticación. Otros temas en esta sección describen cómo crear serializadores y autenticadores personalizados. En este aspecto, crear la clase de credenciales personalizada es el primer tema de la serie. Las acciones subsiguientes (crear serializadores y autenticadores personalizados) sólo se pueden hacer después de crear las credenciales personalizadas. Entre los temas adicionales que se generan a partir de este tema se incluyen:
Procedimiento para crear un proveedor de tokens de seguridad personalizado
Procedimiento para crear un autenticador de tokens de seguridad personalizado
Procedimientos
Para implementar credenciales de cliente personalizadas
Defina una clase nueva derivada de la clase ClientCredentials.
Opcional. Agregue nuevos métodos o propiedades para los nuevos tipos de credenciales. Si no agrega nuevos tipos de credencial, no realice este paso. En el ejemplo siguiente se agrega una propiedad
CreditCardNumber
.Invalide el método CreateSecurityTokenManager . La infraestructura de seguridad de WCF llama automáticamente a este método cuando se usa la credencial de cliente personalizada. Este método es responsable de crear y devolver una instancia de una implementación de la clase SecurityTokenManager.
Importante
Es importante tener en cuenta que el método CreateSecurityTokenManager se invalida para crear un administrador de tokens de seguridad personalizado. El administrador de tokens de seguridad, derivado de ClientCredentialsSecurityTokenManager, debe devolver un proveedor de tokens de seguridad personalizado, derivado de SecurityTokenProvider, para crear el token de seguridad propiamente dicho. Si no sigue este patrón para crear los tokens de seguridad, la aplicación puede tener un funcionamiento incorrecto al almacenar los objetos ChannelFactory en la memoria caché (que es el comportamiento predeterminado para los servidores proxy de cliente de WCF), lo que puede producir un ataque de elevación de privilegios. El objeto de credencial personalizado se almacena en memoria caché como parte de la clase ChannelFactory. Sin embargo, la clase SecurityTokenManager personalizada se crea en cada invocación, lo que mitiga la amenaza de seguridad siempre que la lógica de creación de tokens se sitúe en la clase SecurityTokenManager.
Invalide el método CloneCore .
public class MyClientCredentials : ClientCredentials { string creditCardNumber; public MyClientCredentials() { // Perform client credentials initialization. } protected MyClientCredentials(MyClientCredentials other) : base(other) { // Clone fields defined in this class. this.creditCardNumber = other.creditCardNumber; } public string CreditCardNumber { get { return this.creditCardNumber; } set { if (value == null) { throw new ArgumentNullException("value"); } this.creditCardNumber = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { // Return your implementation of the SecurityTokenManager. return new MyClientCredentialsSecurityTokenManager(this); } protected override ClientCredentials CloneCore() { // Implement the cloning functionality. return new MyClientCredentials(this); } }
Public Class MyClientCredentials Inherits ClientCredentials Private creditCardNumberValue As String Public Sub New() End Sub ' Perform client credentials initialization. Protected Sub New(ByVal other As MyClientCredentials) MyBase.New(other) ' Clone fields defined in this class. Me.creditCardNumberValue = other.creditCardNumberValue End Sub Public Property CreditCardNumber() As String Get Return Me.creditCardNumberValue End Get Set If value Is Nothing Then Throw New ArgumentNullException("value") End If Me.creditCardNumberValue = value End Set End Property Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager ' Return your implementation of the SecurityTokenManager. Return New MyClientCredentialsSecurityTokenManager(Me) End Function Protected Overrides Function CloneCore() As ClientCredentials ' Implement the cloning functionality. Return New MyClientCredentials(Me) End Function End Class
Para implementar un administrador de tokens de seguridad de cliente personalizados
Defina una clase nueva derivada a partir de ClientCredentialsSecurityTokenManager.
Opcional. Invalide el método CreateSecurityTokenProvider(SecurityTokenRequirement) si se debe crear una implementación de SecurityTokenProvider personalizada. Para más información sobre los proveedores de tokens de seguridad personalizados, consulte Procedimiento para crear un proveedor de tokens de seguridad personalizado.
Opcional. Invalide el método CreateSecurityTokenAuthenticator(SecurityTokenRequirement, SecurityTokenResolver) si se debe crear una implementación de SecurityTokenAuthenticator personalizada. Para más información sobre los autenticadores de tokens de seguridad personalizados, consulte Procedimiento para crear un autenticador de tokens de seguridad personalizado.
Opcional. Invalide el método CreateSecurityTokenSerializer si se debe crear un SecurityTokenSerializer personalizado. Para más información sobre los tokens de seguridad personalizados y los serializadores de tokens de seguridad personalizados, consulte Procedimiento para crear un token personalizado.
internal class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager { MyClientCredentials credentials; public MyClientCredentialsSecurityTokenManager(MyClientCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider( SecurityTokenRequirement tokenRequirement) { // Return your implementation of the SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator( SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { // Return your implementation of the SecurityTokenAuthenticator, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { // Return your implementation of the SecurityTokenSerializer, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenSerializer(version); } }
Friend Class MyClientCredentialsSecurityTokenManager Inherits ClientCredentialsSecurityTokenManager Private credentials As MyClientCredentials Public Sub New(ByVal credentials As MyClientCredentials) MyBase.New(credentials) Me.credentials = credentials End Sub Public Overrides Function CreateSecurityTokenProvider( _ ByVal tokenRequirement As SecurityTokenRequirement) As SecurityTokenProvider ' Return your implementation of the SecurityTokenProvider, if required. ' This implementation delegates to the base class. Return MyBase.CreateSecurityTokenProvider(tokenRequirement) End Function Public Overrides Function CreateSecurityTokenAuthenticator( _ ByVal tokenRequirement As SecurityTokenRequirement, _ ByRef outOfBandTokenResolver As SecurityTokenResolver) As SecurityTokenAuthenticator ' Return your implementation of the SecurityTokenAuthenticator, if required. ' This implementation delegates to the base class. Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver) End Function Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) _ As SecurityTokenSerializer ' Return your implementation of the SecurityTokenSerializer, if required. ' This implementation delegates to the base class. Return MyBase.CreateSecurityTokenSerializer(version) End Function End Class
Para usar credenciales de cliente personalizadas a partir del código de la aplicación
Cree una instancia del cliente generado que representa la interfaz de servicio, o cree una instancia del ChannelFactory que señale a un servicio con el que desee comunicarse.
Elimine el comportamiento de credenciales de cliente proporcionadas por el sistema de la colección Behaviors, a la que se puede tener acceso mediante la propiedad Endpoint.
Cree una nueva instancia de una clase de credenciales de cliente personalizada y agréguela a la colección Behaviors, a la que se puede tener acceso mediante la propiedad Endpoint.
// Create a client with the client endpoint configuration. CalculatorClient client = new CalculatorClient(); // Remove the ClientCredentials behavior. client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>(); // Add a custom client credentials instance to the behaviors collection. client.ChannelFactory.Endpoint.Behaviors.Add(new MyClientCredentials());
' Create a client with the client endpoint configuration. Dim client As New CalculatorClient() ' Remove the ClientCredentials behavior. client.ChannelFactory.Endpoint.Behaviors.Remove(Of ClientCredentials)() ' Add a custom client credentials instance to the behaviors collection. client.ChannelFactory.Endpoint.Behaviors.Add(New MyClientCredentials())
El procedimiento anterior muestra cómo usar las credenciales de cliente del código de aplicación. También se pueden configurar credenciales de WCF usando el archivo de configuración de la aplicación. A menudo, es preferible utilizar la configuración de la aplicación en lugar de emplear codificación de forma rígida, porque permite modificar los parámetros de la aplicación sin tener que modificar la fuente, recompilar y reimplementar.
El siguiente procedimiento describe cómo proporcionar compatibilidad para la configuración de credenciales personalizadas.
Creación de un controlador de configuración para las credenciales de cliente personalizadas
Defina una clase nueva derivada a partir de ClientCredentialsElement.
Opcional. Agregue propiedades para todos los parámetros de configuración adicionales que desee exponer a través de la configuración de la aplicación. El siguiente ejemplo agrega una propiedad denominada
CreditCardNumber
.Invalide la propiedad BehaviorType para devolver el tipo de la clase de credenciales de cliente personalizadas creado con el elemento de configuración.
Invalide el método CreateBehavior . El método es responsable de crear y devolver una instancia de la clase de credenciales personalizadas basándose en los ajustes cargados desde el archivo de configuración. Llame al método ApplyConfiguration(ClientCredentials) base desde este método para recuperar los ajustes de credenciales proporcionados por el sistema cargados en su instancia de credenciales de cliente personalizadas.
Opcional. Si agregó propiedades adicionales en el paso 2, ha de invalidar la propiedad Properties para registrar su configuración adicional para que el marco de configuración las reconozca. Combine sus propiedades con las propiedades de clase base para permitir que los ajustes proporcionados por el sistema se configuren a través de este elemento de configuración de credenciales de cliente personalizadas.
public class MyClientCredentialsConfigHandler : ClientCredentialsElement { ConfigurationPropertyCollection properties; public override Type BehaviorType { get { return typeof(MyClientCredentials); } } public string CreditCardNumber { get { return (string)base["creditCardNumber"]; } set { if (String.IsNullOrEmpty(value)) { value = String.Empty; } base["creditCardNumber"] = value; } } protected override ConfigurationPropertyCollection Properties { get { if (this.properties == null) { ConfigurationPropertyCollection properties = base.Properties; properties.Add(new ConfigurationProperty( "creditCardNumber", typeof(System.String), string.Empty, null, new StringValidator(0, 32, null), ConfigurationPropertyOptions.None)); this.properties = properties; } return this.properties; } } protected override object CreateBehavior() { MyClientCredentials creds = new MyClientCredentials(); creds.CreditCardNumber = CreditCardNumber; base.ApplyConfiguration(creds); return creds; } }
Public Class MyClientCredentialsConfigHandler Inherits ClientCredentialsElement Private propertiesValue As ConfigurationPropertyCollection Public Overrides ReadOnly Property BehaviorType() As Type Get Return GetType(MyClientCredentials) End Get End Property Public Property CreditCardNumber() As String Get Return CStr(MyBase.Item("creditCardNumber")) End Get Set If String.IsNullOrEmpty(value) Then value = String.Empty End If MyBase.Item("creditCardNumber") = value End Set End Property Protected Overrides ReadOnly Property Properties() As ConfigurationPropertyCollection Get If Me.propertiesValue Is Nothing Then Dim myProperties As ConfigurationPropertyCollection = MyBase.Properties myProperties.Add(New ConfigurationProperty( _ "creditCardNumber", _ GetType(System.String), _ String.Empty, _ Nothing, _ New StringValidator(0, 32, Nothing), _ ConfigurationPropertyOptions.None)) Me.propertiesValue = myProperties End If Return Me.propertiesValue End Get End Property Protected Overrides Function CreateBehavior() As Object Dim creds As New MyClientCredentials() creds.CreditCardNumber = Me.CreditCardNumber MyBase.ApplyConfiguration(creds) Return creds End Function End Class
Una vez que tenga tiene la clase del controlador de configuración, puede integrarse en el marco de configuración de WCF. Eso permite que las credenciales de cliente personalizadas se usen en los elementos de comportamiento de extremo de cliente, tal y como se muestra en el siguiente procedimiento.
Para registrar y usar un controlador de configuración de credenciales de cliente personalizadas en la configuración de la aplicación
Agregue un elemento
<extensions>
y un elemento<behaviorExtensions>
al archivo de configuración.Agregue un elemento
<add>
al elemento<behaviorExtensions>
y establezca el atributoname
en un valor adecuado.Establezca el atributo
type
en el nombre de tipo completo. Incluya también el nombre de ensamblado y otros atributos de ensamblado.<system.serviceModel> <extensions> <behaviorExtensions> <add name="myClientCredentials" type="Microsoft.ServiceModel.Samples.MyClientCredentialsConfigHandler, CustomCredentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </behaviorExtensions> </extensions> </system.serviceModel>
Después de registrar su controlador de configuración, el elemento de credenciales personalizadas se puede usar dentro del mismo archivo de configuración en lugar del elemento
<clientCredentials>
proporcionado por el sistema. Puede utilizar las propiedades proporcionadas por el sistema y cualquier propiedad nueva que haya agregado a su implementación del controlador de configuración. El siguiente ejemplo establece el valor de una propiedad personalizada mediante el atributocreditCardNumber
.<behaviors> <endpointBehaviors> <behavior name="myClientCredentialsBehavior"> <myClientCredentials creditCardNumber="123-123-123"/> </behavior> </endpointBehaviors> </behaviors>
Para implementar credenciales de servicio personalizadas
Defina una clase nueva derivada a partir de ServiceCredentials.
Opcional. Agregue nuevas propiedades para proporcionar API para los nuevos valores de credenciales que se están agregando. Si no agrega nuevos valores de credenciales, no realice este paso. En el siguiente ejemplo se agrega una propiedad
AdditionalCertificate
.Invalide el método CreateSecurityTokenManager . La infraestructura de WCF llama automáticamente a este método cuando se utiliza la credencial de cliente personalizada. El método es responsable de crear y devolver una instancia de una implementación de la clase SecurityTokenManager(descrita en el siguiente procedimiento).
Opcional. Invalide el método CloneCore . Esto sólo se requiere si se agregan nuevas propiedades o campos internos a la implementación de credenciales de cliente personalizadas.
public class MyServiceCredentials : ServiceCredentials { X509Certificate2 additionalCertificate; public MyServiceCredentials() { } protected MyServiceCredentials(MyServiceCredentials other) : base(other) { this.additionalCertificate = other.additionalCertificate; } public X509Certificate2 AdditionalCertificate { get { return this.additionalCertificate; } set { if (value == null) { throw new ArgumentNullException("value"); } this.additionalCertificate = value; } } public override SecurityTokenManager CreateSecurityTokenManager() { return base.CreateSecurityTokenManager(); } protected override ServiceCredentials CloneCore() { return new MyServiceCredentials(this); } }
Public Class MyServiceCredentials Inherits ServiceCredentials Private additionalCertificateValue As X509Certificate2 Public Sub New() End Sub Protected Sub New(ByVal other As MyServiceCredentials) MyBase.New(other) Me.additionalCertificate = other.additionalCertificate End Sub Public Property AdditionalCertificate() As X509Certificate2 Get Return Me.additionalCertificateValue End Get Set If value Is Nothing Then Throw New ArgumentNullException("value") End If Me.additionalCertificateValue = value End Set End Property Public Overrides Function CreateSecurityTokenManager() As SecurityTokenManager Return MyBase.CreateSecurityTokenManager() End Function Protected Overrides Function CloneCore() As ServiceCredentials Return New MyServiceCredentials(Me) End Function End Class
Para implementar un administrador de tokens de seguridad de servicio personalizados
Defina una clase nueva derivada de la clase ServiceCredentialsSecurityTokenManager.
Opcional. Invalide el método CreateSecurityTokenProvider si se debe crear una implementación de SecurityTokenProvider personalizada. Para más información sobre los proveedores de tokens de seguridad personalizados, consulte Procedimiento para crear un proveedor de tokens de seguridad personalizado.
Opcional. Invalide el método CreateSecurityTokenAuthenticator si se debe crear una implementación de SecurityTokenAuthenticator personalizada. Para más información sobre los autenticadores de tokens de seguridad personalizados, consulte el tema Procedimiento para crear un autenticador de tokens de seguridad personalizado.
Opcional. Invalide el método CreateSecurityTokenSerializer(SecurityTokenVersion) si se debe crear un SecurityTokenSerializer personalizado. Para más información sobre los tokens de seguridad personalizados y los serializadores de tokens de seguridad personalizados, consulte Procedimiento para crear un token personalizado.
internal class MyServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager { MyServiceCredentials credentials; public MyServiceCredentialsSecurityTokenManager(MyServiceCredentials credentials) : base(credentials) { this.credentials = credentials; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { // Return your implementation of SecurityTokenProvider, if required. // This implementation delegates to the base class. return base.CreateSecurityTokenSerializer(version); } }
Friend Class MyServiceCredentialsSecurityTokenManager Inherits ServiceCredentialsSecurityTokenManager Private credentials As MyServiceCredentials Public Sub New(ByVal credentials As MyServiceCredentials) MyBase.New(credentials) Me.credentials = credentials End Sub Public Overrides Function CreateSecurityTokenProvider(ByVal tokenRequirement As SecurityTokenRequirement) _ As SecurityTokenProvider ' Return your implementation of SecurityTokenProvider, if required. ' This implementation delegates to the base class. Return MyBase.CreateSecurityTokenProvider(tokenRequirement) End Function Public Overrides Function CreateSecurityTokenAuthenticator( _ ByVal tokenRequirement As SecurityTokenRequirement, _ ByRef outOfBandTokenResolver As SecurityTokenResolver) _ As SecurityTokenAuthenticator ' Return your implementation of SecurityTokenProvider, if required. ' This implementation delegates to the base class. Return MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, outOfBandTokenResolver) End Function Public Overrides Function CreateSecurityTokenSerializer(ByVal version As SecurityTokenVersion) _ As SecurityTokenSerializer ' Return your implementation of SecurityTokenProvider, if required. ' This implementation delegates to the base class. Return MyBase.CreateSecurityTokenSerializer(version) End Function End Class
Para usar credenciales de servicio personalizadas a partir del código de la aplicación
Creación de una instancia de ServiceHost.
Elimine el comportamiento de las credenciales de servicio proporcionadas por el sistema desde la colección Behaviors.
Cree una nueva instancia de la clase de credenciales de servicio personalizadas y agréguela a la colección Behaviors.
// Create a service host with a service type. ServiceHost serviceHost = new ServiceHost(typeof(Service)); // Remove the default ServiceCredentials behavior. serviceHost.Description.Behaviors.Remove<ServiceCredentials>(); // Add a custom service credentials instance to the collection. serviceHost.Description.Behaviors.Add(new MyServiceCredentials());
' Create a service host with a service type. Dim serviceHost As New ServiceHost(GetType(Service)) ' Remove the default ServiceCredentials behavior. serviceHost.Description.Behaviors.Remove(Of ServiceCredentials)() ' Add a custom service credentials instance to the collection. serviceHost.Description.Behaviors.Add(New MyServiceCredentials())
Agregue compatibilidad con la configuración mediante los pasos descritos anteriormente en los procedimientos "To create a configuration handler for custom client credentials
" y "To register and use a custom client credentials configuration handler in the application configuration
". La única diferencia es usar la clase ServiceCredentialsElement en lugar de la clase ClientCredentialsElement como una clase base para el controlador de configuración. El elemento de credencial de servicio personalizado puede utilizarse después dondequiera que se utilice el elemento <serviceCredentials>
proporcionado por el sistema.
Consulte también
- ClientCredentials
- ServiceCredentials
- SecurityCredentialsManager
- SecurityTokenManager
- ClientCredentialsElement
- ServiceCredentialsElement
- Procedimiento para crear un proveedor de tokens de seguridad personalizado
- Procedimiento para crear un autenticador de tokens de seguridad personalizado
- Procedimiento para crear un token personalizado