2010-12-04 21 views
9

He estado luchando con la configuración de este maldito servicio WCF durante la última semana, y estoy disminuyendo el tiempo al sospechar que lo que estoy tratando de hacer simplemente no es posible , a pesar de la documentación.Autenticación de una Solicitud de WCF a través de un Certificado de Cliente a través de HTTPS

Simplemente, quiero tener un servicio WCF que requiera un certificado de cliente (que el servidor tendrá en su almacén de certificados), y luego acceder a esa identidad con System.ServiceModel.ServiceSecurityContext. Además, esto necesita usar seguridad de transporte.

Aquí está mi configuración del servidor:

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

Aquí está mi configuración del cliente:

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

El código todo funciona perfectamente cuando el modo de seguridad = 'Ninguno' a través de HTTP, pero por supuesto, no hay autenticación y nada en System.ServiceModel.ServiceSecurityContext. He intentado docenas de variaciones en todos estos elementos, y todo termina inevitablemente con la solicitud lanzando una excepción "Una conexión existente fue cerrada a la fuerza por el host remoto".

Estoy usando un certificado autofirmado "CyberdyneIndustries", cuyo certificado de CA he agregado a la tienda de CA de confianza. El certificado se retira cuando lo veo. He pasado por el infierno de la administración del espacio de nombres http y también he resuelto esos problemas. Simplemente parece que WCF realmente no es compatible con esto ... por favor dime que estoy equivocado.

TIA.

Respuesta

2

En última instancia, decidí probar la seguridad del mensaje, para ver si eso arrojaría algo de luz sobre la situación, y lo hice, y voy a reducir mis pérdidas y seguir con eso. Entonces, no hay una respuesta definitiva a esto.

La implementación de la seguridad de los mensajes, sin embargo, expone un GRAN problema, y ​​esta puede haber sido la raíz del problema de seguridad del transporte. Hay una parte de la documentación veneno de MSDN:

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

En esta página, el comando para crear el certificado autofirmado es el siguiente:

makecert -sk MyKeyName -IV RootCaClientTest .pvk -n "CN = tempClientcert" -ic RootCaClientTest.cer -sr CurrentUser -SS mi firma -sky -pe

El argumento "firma" debería ser "intercambio". Una vez que regeneré todos mis certs, la seguridad de los mensajes comenzó a funcionar. Una gran conclusión de todo esto es que si desea implementar la seguridad del transporte, la seguridad de los mensajes funciona primero, porque los mensajes de error que obtiene del sistema son mucho más descriptivos.

0

WsHttpBinding DOES admite la autenticación de certificados para la seguridad del transporte.

No puede haber algunas cosas equivocadas:

  1. ¿Ha agregado ambos certificados a su tienda? ¿Ciberdyne Industries también una CA que usaste para firmarlo? CA debe estar en "Autoridades de certificación raíz de confianza"

  2. Además, he hecho esto alojado automáticamente, nunca en el servidor Visual Studio Dev. Intente alojar su servicio en IIS al menos. No estoy seguro de si el servidor VS Dev admite certificados.

  3. Intenta desactivar la autenticación del servicio. Entonces el cliente no tiene que autenticar el servicio. No sé si desea que esta en su aplicación o no, pero sólo para las pruebas por lo que puedo descartar eso

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

1

¿Tiene éxito el protocolo de enlace SSL? Habilite el registro de SChannel para solucionar problemas de la capa SSL. Ver este viejo artículo de KB: How to enable Schannel event logging in IIS. Aunque es una KB para W2K y XP, los pasos para habilitar el registro de SChannel son los mismos y siguen siendo válidos en los sistemas más nuevos. Con el registro habilitado, podrá determinar por qué SSL rechaza el certificado.

1

Sé que esto es de 3 años de edad, pero para los que todavía podía interesarle ...

estoy en el proceso de aprendizaje de WCF (seguridad entre otras cosas) y fue capaz de conseguir cosas funcionan correctamente con netTcpBinding (presumiblemente, esto también funcionará para WsHttpBindings) utilizando el modo de seguridad de transporte con un clientCredentialType = "Certificate" (y, protectionLevel = "EncryptAndSign", aunque eso no guardaba relación con el problema).

Encontré el error de cierre de conexión forzada desde el servidor también, pero descubrí que me faltaba una configuración. Todo está funcionando ahora.

Aquí está mi configuración del lado del servidor:

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

Y mi configuración del lado del cliente:

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

he creado una cadena de certificados para el servidor (certificado raíz de confianza autofirmado + un certificado construido usando esa raíz) usando la técnica descrita here y almacenando tanto el certificado raíz como el certificado hijo en el almacén de certificados de la máquina host de mi servidor. Y, finalmente, importé ese certificado de servidor + clave pública en la tienda de certificaciones en mi equipo host cliente (en LocalMachine/TrustedPeople).

Cuestiones relacionadas