2010-12-04 38 views
9

J'ai été aux prises avec la configuration de ce fustigé le service WCF pour la semaine dernière, et je ralentir début de penser que ce que je suis en train de faire est tout simplement pas possible , malgré la documentation. Tout simplement, je veux qu'un service WCF requière un certificat client (que le serveur aura dans son magasin de certificats), puis accède à cette identité avec System.ServiceModel.ServiceSecurityContext. En outre, cela doit utiliser la sécurité du transport.une demande d'authentification par certificat client WCF via HTTPS

Voici mon config serveur:

<system.serviceModel> 
    <services> 
     <service behaviorConfiguration="requireCertificate" name="Server.CXPClient"> 
     <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="PartnerComm.ContentXpert.Server.ICXPClient" /> 
     <endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="mexEndpoint" contract="IMetadataExchange" /> 
     <host> 
      <baseAddresses> 
      <add baseAddress="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/" /> 
      </baseAddresses> 
     </host> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="requireCertificate"> 
      <serviceMetadata httpsGetEnabled="true" /> 
      <serviceCredentials> 
      <serviceCertificate findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/> 
      <clientCertificate> 
       <authentication certificateValidationMode="ChainTrust" trustedStoreLocation="LocalMachine" /> 
      </clientCertificate> 
      </serviceCredentials> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <wsHttpBinding> 
     <binding name="wsHttpEndpointBinding" maxBufferPoolSize="5242880" maxReceivedMessageSize="5242880"> 
      <readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="1073741824" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" /> 
      </security> 
     </binding> 
     </wsHttpBinding> 
    </bindings> 
    </system.serviceModel> 

Voici mon client config:

<system.serviceModel> 
    <bindings> 
     <wsHttpBinding> 
     <binding name="wsHttpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" 
      receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" 
      transactionFlow="false" hostNameComparisonMode="StrongWildcard" 
      maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" 
      textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> 
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
      maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
      <reliableSession ordered="true" inactivityTimeout="00:10:00" 
      enabled="false" /> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" /> 
      </security> 
     </binding> 
     </wsHttpBinding> 
    </bindings> 
    <client> 
     <endpoint address="https://localhost:8371/Design_Time_Addresses/Server/CXPClient/" 
     binding="wsHttpBinding" bindingConfiguration="wsHttpEndpoint" behaviorConfiguration="ClientCertificateBehavior" 
     contract="ContentXPertServer.ICXPClient" name="wsHttpEndpoint" /> 
    </client> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior name="ClientCertificateBehavior"> 
      <clientCredentials> 
      <clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" /> 
      </clientCredentials> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    </system.serviceModel> 

Le code tout fonctionne parfaitement lorsque le mode de sécurité = 'None' sur http, mais bien sûr, il n'y a pas d'authentification et rien dans System.ServiceModel.ServiceSecurityContext. J'ai essayé des douzaines de variations sur tous ces éléments, et tout cela finit inévitablement par la requête en lançant une exception "Une connexion existante a été fermée de force par l'hôte distant".

J'utilise un cert « CyberdyneIndustries » auto-signé, dont le CA cert j'ai ajouté au magasin CA de confiance. Le cert vérifie quand je le vois. J'ai traversé l'enfer de la gestion de l'espace de noms http, et j'ai également résolu ces problèmes. Il semble simplement que WCF ne supporte pas vraiment cela ... s'il vous plaît dites-moi que je me trompe.

TIA.

Répondre

2

En fin de compte, j'ai décidé d'essayer la sécurité des messages, pour voir si cela faire la lumière sur la situation - il l'a fait, et je vais réduire mes pertes et aller avec cela. Donc, il n'y a pas de réponse définitive à cela.

Cependant, la mise en œuvre de la sécurité des messages ne, exposer un gros problème, et cela aurait pu être la racine du problème de la sécurité des transports. Il y a une partie de la documentation de poison de MSDN:

http://msdn.microsoft.com/en-us/library/ff650751.aspx

Sur cette page, la commande pour créer le certificat auto-signé est la suivante:

makecert sk MyKeyName -iv RootCaClientTest .pvk -n "CN = tempClientcert" -ique RootCaClientTest.cer -SR currentuser -ss ma signature -sky -pe

L'argument "signature" devrait plutôt être "échange". Une fois que j'ai régénéré tous mes certs, la sécurité des messages a commencé à fonctionner. Un gros point à retenir de tout cela est que si vous voulez implémenter la sécurité du transport, assurez-vous que la sécurité des messages fonctionne en premier, car les messages d'erreur que vous obtenez du système sont beaucoup plus descriptifs.

0

WSHttpBinding gère l'authentification du certificat de soutien à la sécurité des transports.

Il peut y avoir quelques mauvaises choses:

  1. Avez-vous ajouté les deux certificats à votre magasin? CyberdyneIndustries ainsi qu'un CA que vous avez utilisé pour le signer? L'autorité de certification doit être dans les "Autorités de certification racines de confiance"

  2. De plus, j'ai effectué cette auto-hébergement, jamais dans le serveur Visual Studio Dev. Essayez d'héberger votre service dans IIS au moins. Je ne suis pas sûr si le serveur VS Dev supporte les certificats.

  3. Essayez de désactiver l'authentification de service. Ainsi, le client n'a pas besoin d'authentifier le service. Je ne sais pas si vous voulez dans votre application ou non, mais juste pour le test afin que nous puissions exclure cette

    <behavior name="ClientCertificateBehavior"> 
    <clientCredentials> 
        <clientCertificate x509FindType="FindBySubjectName" findValue="CyberdyneIndustries" storeLocation="LocalMachine" storeName="TrustedPeople" /> 
        <serviceCertificate> 
         <authentication certificateValidationMode="None"/> 
        </serviceCertificate> 
    </clientCredentials> 
    

1

La réussite connexion SSL? Activez la journalisation SChannel pour dépanner la couche SSL. Voir cet ancien article de la base de connaissances: How to enable Schannel event logging in IIS. Bien qu'il s'agisse d'une base de connaissances pour W2K et XP, les étapes permettant d'activer la journalisation SChannel sont les mêmes et restent valables sur les nouveaux systèmes. Avec la journalisation activée, vous serez en mesure de déterminer pourquoi SSL rejette le certificat.

1

Je sais que c'est de 3 ans, mais pour ceux qui pourraient encore être intéressé ...

Je suis dans le processus d'apprentissage WCF (sécurité entre autres) et a été en mesure de faire avancer les choses fonctionnent correctement avec netTcpBinding (probablement, cela fonctionnera aussi pour WsHttpBindings) en utilisant le mode de sécurité Transport avec un clientCredentialType = "Certificate" (et, protectionLevel = "EncryptAndSign", bien que cela ne soit pas pertinent pour le problème).

J'ai rencontré l'erreur de fermeture de connexion forcée du côté serveur, mais j'ai découvert qu'il me manquait un élément de configuration. Tout fonctionne maintenant.

Voici mon config côté serveur:

<configuration> 
    <system.serviceModel> 
    <services> 
     <service name="MyNamespace.MyService" behaviorConfiguration="MyServiceBehavior"> 
     <endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding" bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService" /> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="MyServiceBehavior"> 
      <serviceCredentials> 
      <serviceCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /> 
      <clientCertificate> 
       <authentication certificateValidationMode="PeerTrust"/> 
      </clientCertificate> 
      </serviceCredentials> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <netTcpBinding> 
     <binding name="TcpCertSecurity"> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" /> 
      </security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    </system.serviceModel> 
</configuration> 

Et ma configuration côté client:

<configuration> 
    <system.serviceModel> 
    <client> 
     <endpoint address="net.tcp://localhost:9002/MyServer" binding="netTcpBinding" 
      bindingConfiguration="TcpCertSecurity" contract="MyNamespace.IMyService" 
      behaviorConfiguration="MyServiceBehavior"> 
     <identity> 
      <dns value="MyServiceCert" /> 
     </identity> 
     </endpoint> 
    </client> 
    <bindings> 
     <netTcpBinding> 
     <binding name="TcpCertSecurity"> 
      <security mode="Transport"> 
      <transport clientCredentialType="Certificate" protectionLevel="EncryptAndSign" /> 
      </security> 
     </binding> 
     </netTcpBinding> 
    </bindings> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior name="MyServiceBehavior"> 
      <clientCredentials> 
      <serviceCertificate> 
       <authentication certificateValidationMode="PeerTrust" /> 
      </serviceCertificate> 
      <clientCertificate findValue="MyServiceCert" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" /> 
      </clientCredentials> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    </system.serviceModel> 
</configuration> 

J'ai créé une chaîne de certificats pour le serveur (Trusted auto-signé certificat racine + un certificat construit en utilisant cette racine) en utilisant la technique décrite here et stocké à la fois le certificat racine et le certificat enfant dans le magasin de certificats de mon ordinateur hôte du serveur. Enfin, j'ai importé ce certificat de serveur + clé publique dans le magasin de certificats sur mon ordinateur hôte client (dans LocalMachine/TrustedPeople).