with usuario secure password custom contraseña clientcredentialtype autenticacion and c# wcf web-services authentication token

c# - usuario - Autenticación WCF con ClientCredentials personalizadas: ¿Cuál es el clientCredentialType para usar?



wcf login c# (1)

Me encontré con problemas similares con una aplicación en la que estoy trabajando. Desafortunadamente, me rendí porque no podía trabajar con las credenciales personalizadas. Ahora estoy usando el nombre de usuario / contraseña (credenciales del cliente) y el certificado (credenciales de servicio) con encabezados jabonados encriptados personalizados agregados a las llamadas de servicio para pasar información adicional, por ejemplo, identificación de usuario, etc.

Tuve que deshacerme de la seguridad WCF UserName / Pwd básica e implementar mis propias credenciales de cliente personalizadas para guardar algo de información más allá de lo que se proporciona de forma predeterminada.

Trabajé en este artículo de MSDN , pero me falta algo porque no funciona.

En primer lugar, tengo algunas ClientCredentials personalizadas que proporcionan un ClientCredentialsSecurityTokenManager personalizado:

public class CentralAuthCredentials : ClientCredentials { public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager() { return new CentralAuthTokenManager(this); } } public class CentralAuthTokenManager : ClientCredentialsSecurityTokenManager { private CentralAuthCredentials credentials; public CentralAuthTokenManager(CentralAuthCredentials creds) : base(creds) { this.credentials = creds; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) return new CentralAuthTokenProvider(credentials.UserId, credentials.UserPassword, credentials.ImpersonateId, credentials.LoginType); else return base.CreateSecurityTokenProvider(tokenRequirement); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { outOfBandTokenResolver = null; if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) return new CentralAuthTokenAuthenticator(); else return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { return new CentralAuthTokenSerializer(); } }

Ahora cuando ejecuto la aplicación, se crean mis credenciales personalizadas y token manager. Sin embargo, en el método:

CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { ... }

El tokenRequirement.TokenType aparece como algo más que mi token personalizado. Eso me lleva a mi primera pregunta : ¿Cómo diablos sabe WCF cuáles son los requisitos del token?

Además, el método:

public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { return new CentralAuthTokenSerializer(); }

El cliente lo llama una vez, pero nunca se llama a ninguno de los métodos del serializador de tokens devueltos. Esto me indica que el token personalizado nunca se envía a través del cable. Supongo que esto se debe a que la llamada a CreateSecurityTokenProvider () nunca devolvió mi proveedor de token personalizado, ya que el SecurityTokenRequirement nunca se pasa para indicar que se necesita mi token personalizado.

En el lado del cliente, tengo:

public class CentralAuthorizationManagerClient : ClientBase<ICentralAuthorizationManager>, ICentralAuthorizationManager, IDisposable { public PFPrincipal GenerateToken() { if (!this.ChannelFactory.Endpoint.Behaviors.Contains(typeof(CentralAuthCredentials))) throw new ArgumentException("Must set CentralAuthCredentials before calling this method."); return base.Channel.GenerateToken(); } public PFPrincipal GenerateToken(CentralAuthToken token) { this.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>(); this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token)); return this.GenerateToken(); }

Se supone que estos métodos básicamente eliminan las credenciales predeterminadas del punto final y adjuntan una nueva instancia de mi CentralAuthCredentials personalizada. (Cogí este combo Eliminar / Agregar de un artículo de MSDN en algún lugar).

En la configuración:

<behaviors> <endpointBehaviors> <behavior name="Server2ServerEndpointBehavior"> <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp"> <clientCertificate findValue="localhost" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" /> <serviceCertificate> <authentication certificateValidationMode="None" revocationMode="NoCheck" /> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <bindings> <wsHttpBinding> <binding name="wsHttpServer2Server"> <security mode="Message"> <message clientCredentialType="UserName" /> </security> </binding> </wsHttpBinding> </bindings>

Tenga en cuenta que el tipo clientCredentials del comportamiento se establece en mis credenciales de cliente personalizadas. Sin embargo, en este momento todavía tengo el clientCredentialType del enlace establecido en "UserName". Esto me lleva a mi segunda pregunta : ¿Qué diablos debería clientCredentialType = "?" establecerse en si estoy usando credenciales personalizadas? Según MSDN, los valores disponibles para la seguridad del mensaje son: Ninguno , Windows , Nombre de usuario , Certificado y IssuedToken .

¿Algunas ideas? Espero que me esté perdiendo algo simple? Hay como 6 clases más para toda la implementación, pero traté de incluir solo los bits necesarios para comprender la situación ...

ACTUALIZACIÓN # 1:

He estado trabajando en esto todo el día, y gracias a algunas fuentes, me di cuenta de que parte de lo que me faltaba era el último paso en esta página , que es agregar los TokenParameters al enlace, de modo que el enlace sepa qué el token parece. Esa es la respuesta a mi primera pregunta original; "¿Qué demonios establece los requisitos del token?" Respuesta: los TokenParameters asignados al enlace.

Así que ahora agregué la siguiente extensión que establece TokenParameters en el enlace:

public sealed class CentralAuthTokenBindingExtension : BindingElementExtensionElement { public CentralAuthTokenBindingExtension() : base() { } public override Type BindingElementType { get { return typeof(SymmetricSecurityBindingElement); } } protected override System.ServiceModel.Channels.BindingElement CreateBindingElement() { X509SecurityTokenParameters protectionParams = new X509SecurityTokenParameters(); protectionParams.InclusionMode = SecurityTokenInclusionMode.Never; SymmetricSecurityBindingElement innerBindingElement = new SymmetricSecurityBindingElement(); innerBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CentralAuthTokenParameters()); //innerBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; innerBindingElement.ProtectionTokenParameters = protectionParams; return innerBindingElement; } } <extensions> <bindingElementExtensions> <add name="CentralAuthCreds" type="MyApp.Security.Configuration.CentralAuthTokenBindingExtension, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </bindingElementExtensions> </extensions> <bindings> <customBinding> <binding name="wsHttpServer2Server"> <CentralAuthCreds /> <binaryMessageEncoding /> <httpTransport /> </binding> </customBinding> </bindings>

Bueno, eso me lleva un paso más allá. Ahora recibo una nueva excepción en el servidor:

"The security token manager cannot create a token authenticator for requirement ..."

Parece que WCF está usando un gestor de tokens predeterminado para intentar tratar con mi token personalizado, en lugar de mi controlador de token personalizado (nunca se llama al constructor de mi gestor de tokens personalizados). Creo que esto está sucediendo porque para el cliente , tengo esta configuración:

<endpointBehaviors> <behavior name="Server2ServerEndpointBehavior"> <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">

Pero en el servidor no tengo ningún equivalente para informarle acerca de las credenciales personalizadas del cliente. Entonces, nueva pregunta : ¿En qué parte de la configuración del servidor le cuento cuáles son las ClientCredentials personalizadas?

Actualización # 2:

Bueno, finalmente descubrí un poco más del rompecabezas. Solo había implementado una implementación ClientCredentials, pensando que el cliente envía credenciales, y eso es todo. El cliente no autentica el servicio, por lo que no necesito ServiceCredentials personalizados. Bueno, estaba equivocado. Las ServiceCredentials especificadas autentican el token de ClientCredentials y viceversa. Así que solo tuve que agregar una implementación de ServiceCredentials personalizada que pasara las mismas clases TokenSerializer y TokenAuthenticator.

Sobre el próximo problema: WCF ahora está ignorando mis certificaciones x509 especificadas en config que funcionaban bien con la autenticación de nombre de usuario. ¡Voy a abrir una nueva pregunta para este!