2009-02-18 10 views
23

J'ai dû abandonner la sécurité WCF UserName/Pwd de base et mettre en œuvre mes propres informations d'identification client personnalisé pour contenir plus d'informations au-delà de ce qui est fourni par défaut.Authentification WCF avec ClientCredentials personnalisé: Quel est le clientCredentialType à utiliser?

J'ai travaillé à this MSDN article, mais il me manque quelque chose parce que cela ne fonctionne pas.

Tout d'abord, j'ai quelques ClientCredentials personnalisés qui offrent une ClientCredentialsSecurityTokenManager personnalisée:

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(); 
    } 
} 

Maintenant, quand je lance l'application, mes lettres de créance personnalisés et gestionnaire de jetons ne soient créés. Cependant, dans la méthode:

CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
{ 
    ... 
} 

Le tokenRequirement.TokenType se présente comme autre chose que mon jeton personnalisé. Cela amène mon 1ère question: Comment diable WCF sait quelles sont les exigences de jeton?

En outre, la méthode:

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

ne s'appelle une fois par le client, mais aucune des méthodes du sérialiseur jeton renvoyé sont jamais appelés. Cela m'indique que le jeton personnalisé n'est jamais envoyé à travers le fil. Je suppose que c'est parce que l'appel à CreateSecurityTokenProvider() n'a jamais renvoyé mon fournisseur de jeton personnalisé, puisque le SecurityTokenRequirement n'est jamais passé en indiquant que mon jeton personnalisé est nécessaire.

Du côté client, je dois:

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(); 
    } 

Ces méthodes sont essentiellement censés supprimer les informations d'identification par défaut du point d'extrémité et joindre une nouvelle instance de mes CentralAuthCredentials personnalisés. (J'ai attrapé ce combo Remove/Add d'un article MSDN quelque part).

Dans la configuration:

<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> 

Notez que est réglé sur mes lettres de créance client personnalisés de type ClientCredentials du comportement. Cependant, pour l'instant, le clientCredentialType de la liaison est toujours défini sur "UserName". Cela soulève ma 2e question: Que diable devrait clientCredentialType = "?" être défini sur si j'utilise des informations d'identification personnalisées? Selon MSDN, les valeurs disponibles pour message sécurité sont: Aucun, de Windows, UserName, certificat et IssuedToken.

Des idées? Espérons que je manque quelque chose de simple? Il y a 6 classes de plus pour l'ensemble de l'implémentation, mais j'ai essayé d'inclure seulement les bits nécessaires pour comprendre la situation ...


MISE À JOUR # 1:

Je travaille sur toute la journée, et grâce à quelques sources, j'ai réalisé qu'une partie de ce que je manquais était la dernière étape sur this page , qui ajoute les TokenParameters à la liaison, de sorte que la liaison sache à quoi ressemble le jeton. C'est la réponse à ma première question originale; "Qu'est-ce que le diable met en place les exigences de jeton?" Réponse: les TokenParameters assignés à la liaison.

Alors maintenant, j'ajouté l'extension suivante qui fixe les TokenParameters sur la liaison:

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> 

bien qui me fait un peu plus loin. Maintenant, je reçois une nouvelle exception sur le serveur:

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

Il ressemble à WCF utilise une partie gestionnaire de jetons par défaut pour essayer de traiter avec mon jeton personnalisé, au lieu de mon gestionnaire jeton sur mesure (constructeur de mon gestionnaire jeton personnalisée est jamais appelé). Je pense ce qui se passe parce que pour le client, j'ai cette config:

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

Mais sur le serveur Je n'ai pas d'équivalent pour le faire savoir sur les informations d'identification client personnalisé. Donc, nouvelle question: Où dans la config pour le serveur est-ce que je lui dis quels sont les customCredentials personnalisés?


Mise à jour # 2:

Eh bien, j'ai finalement trouvé un peu plus du casse-tête. J'avais seulement implémenté une implémentation de ClientCredentials, en pensant que le client envoie des commandes, et c'est tout. Le client n'authentifie pas le service, donc je n'ai pas besoin de ServiceCredentials personnalisé. Eh bien, j'avais tort. Le ServiceCredentials spécifié authentifie le jeton à partir de ClientCredentials, et vice-versa. Je devais donc ajouter une implémentation ServiceCredentials personnalisée qui transmettait les mêmes classes TokenSerializer et TokenAuthenticator.

Sur la question suivante: WCF ne tient pas compte maintenant mes cert x509 spécifiés dans la configuration qui travaillaient très bien avec UserName auth. Je vais ouvrir une toute nouvelle question pour celui-ci!

+0

Ok, donc cette question se lit presque exactement comme mon dernier deux jours! – basscinner

Répondre

1

J'ai couru pour des problèmes similaires avec une application que je travaille, malheureusement, je renonçai que je ne pouvais pas faire fonctionner les informations d'identification personnalisés. Je suis maintenant en utilisant le nom d'utilisateur/mot de passe (informations d'identification du client) et le certificat (les informations d'identification de service) avec les en-têtes de savon crypté personnalisés ajoutés à des appels de service pour passer d'info autour supplémentaires, par exemple UserID etc.

Questions connexes