2009-02-18 12 views
23

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.Autenticación WCF con ClientCredentials personalizadas: ¿Cuál es el clientCredentialType para usar?

He trabajado a través de this MSDN article, pero me falta algo porque no funciona.

En primer lugar, tengo algunas ClientCredentials personalizados que proporcionan una ClientCredentialsSecurityTokenManager encargo:

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 en que funciono la aplicación, mis credenciales personalizados y de gestor de símbolos no se crean. Sin embargo, en el método:

CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
{ 
    ... 
} 

El tokenRequirement.TokenType aparece como algo que no sea mi testigo a medida. 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(); 
} 

se consiga llamar una vez por el cliente, pero ninguno de los métodos en el serializador token devuelto nunca son llamados. 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, que tienen:

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 básicamente Estos métodos para eliminar las credenciales predeterminadas desde el punto final y adjuntar una nueva instancia de mis CentralAuthCredentials personalizados. (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 comportamiento del tipo ClientCredentials se establece en mis credenciales del cliente personalizados. Sin embargo, en este momento todavía tengo el clientCredentialType del enlace establecido en "UserName". Esto abre mi 2da pregunta: ¿Qué diablos debería clientCredentialType = "?" establecerse en si estoy usando credenciales personalizadas? De acuerdo con MSDN, los valores disponibles para la seguridad mensaje son: Ninguno , de Windows, Nombre de usuario, Certificado y IssuedToken.

¿Alguna idea? 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 durante todo el día, y gracias a unas pocas fuentes, me di cuenta de que parte de lo que me faltaba era el último paso en this page , que está agregando TokenParameters al enlace, para que el enlace sepa a qué se parece el token. 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 añade la siguiente extensión que fija los TokenParameters sobre la unión:

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 pone un paso más allá. Ahora consigo una nueva excepción en el servidor:

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

Parece que WCF está usando alguna de gestor de símbolos por defecto para tratar de lidiar con mi testigo a medida, en lugar de mi manejador de testigo a medida (el constructor de mi manejador de testigo a medida no es nunca llamado). Yo creo esto está sucediendo porque para el cliente, tengo esta configuración:

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

Pero en el servidorque no tienen ningún equivalente para hacerle saber acerca de las credenciales del cliente personalizado. Así, nueva pregunta: ¿Dónde en la configuración para el servidor le digo que lo que los ClientCredentials personalizados son?


Actualización # 2:

Bueno, finalmente descubrió 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.

En el próximo número: WCF está haciendo caso omiso de mis certificados x509 especificados en la configuración que estaban trabajando bien con autenticación de usuario. ¡Voy a abrir una nueva pregunta para este!

+0

Ok, por lo que esta cuestión dice casi exactamente igual que mi último ¡dos días! – basscinner

Respuesta

1

me encontré a problemas similares con una aplicación que estoy trabajando, por desgracia, me di por vencido ya que no podía conseguir las credenciales personalizadas de trabajo. Ahora estoy usando nombre de usuario/contraseña (credenciales del cliente) y el certificado (credenciales de servicio) con las cabeceras de jabón personalizados cifrado añadido a las llamadas de servicio para pasar información adicional, por ejemplo alrededor de identificación de usuario, etc.

Cuestiones relacionadas