2011-05-18 20 views
8

He escrito un servicio WCF alojado en sí mismo usando WSHttpBindings y yo estoy tratando de implementar la seguridad a nivel de mensajes utilizando certificados he generado yo. Lamentablemente, recibo una excepción enterrada (a través del visor de seguimiento de servicios) que dice "Las credenciales suministradas al paquete no fueron reconocidas".programático WCF mensaje de seguridad con certificados

Un par de notas:

  1. Esto tiene que ser hecho en código, no en la configuración
  2. (servidor/cliente) Cert son certificados que se encuentran en el almacén de equipo local con claves privadas de acceso a mi usuario durante la depuración.
  3. Googled el infierno fuera de esto y encontré un buen recurso para configurar la seguridad basada mensaje WCF here

No estoy seguro de lo que me falta. La mayoría de estas cosas parece directa, excepto para crear las identidades de punto final. Falla con el mismo mensaje si uso DnsEndpointIdentities, cert based ones, o no identities en absoluto.

¿Alguien puede indicarme la dirección correcta?

lado del servidor:

var binding = new WSHttpBinding 
    { 
     Security = 
     { 
     Mode = SecurityMode.Message, 
     Message = 
     { 
      ClientCredentialType = MessageCredentialType.Certificate, 
      AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15 
     } 
     } 
    }; 

_host = new ServiceHost(this) 
{ 
    Credentials = 
    { 
    ServiceCertificate = 
    { 
     Certificate = ServiceCert 
    }, 
    ClientCertificate = 
    { 
     Certificate = ClientCert, 
     Authentication = 
     { 
     TrustedStoreLocation = StoreLocation.LocalMachine, 
     RevocationMode = X509RevocationMode.NoCheck, 
     CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust 
     } 
    } 
    } 
}; 
var address = new Uri(string.Format(@"http://serviceaddress")); 
var ep = _host.AddServiceEndpoint(typeof (IService), binding, address); 
ep.Address = new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(ServiceCert)); 
_host.Open(); 

lado del cliente:

var binding = new WSHttpBinding 
    { 
     Security = 
     { 
     Mode = SecurityMode.Message, 
     Message = 
     { 
      ClientCredentialType = MessageCredentialType.Certificate, 
      AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15 
     } 
     } 
    }; 
var address = new Uri(@"http://serviceaddress"); 
var endpoint = new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(ServerCert)); 
var channelFactory = new ChannelFactory<IService>(binding, endpoint) 
    { 
     Credentials = 
     { 
     ServiceCertificate = 
     { 
      DefaultCertificate = ServerCert, 
      Authentication = 
      { 
      RevocationMode = X509RevocationMode.NoCheck, 
      TrustedStoreLocation = StoreLocation.LocalMachine, 
      CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust 
      } 
     }, 
     ClientCertificate = 
     { 
      Certificate = ClientCert 
     } 
     } 
    }; 
var channel = channelFactory.CreateChannel(); 

Respuesta

11

this msdn article ayudado enormemente. Creo que la raíz del problema estaba estableciendo los siguientes parámetros de seguridad de los mensajes en false:

httpBinding.Security.Message.NegotiateServiceCredential = false; 
httpBinding.Security.Message.EstablishSecurityContext = false; 

Así que ahora el código general para el lado del servidor se parece más a:

var httpBinding = new WSHttpBinding(SecurityMode.Message); 
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate; 
httpBinding.Security.Message.NegotiateServiceCredential = false; 
httpBinding.Security.Message.EstablishSecurityContext = false; 
var httpUri = new Uri("http://serviceaddress"); 
_host = new ServiceHost(this, httpUri); 
_host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, serverThumbprint); 
_host.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck; 
_host.Credentials.ClientCertificate.Authentication.TrustedStoreLocation = StoreLocation.LocalMachine; 
_host.AddServiceEndpoint(typeof(IMetaService), httpBinding, httpUri); 
_host.Open(); 

y el lado del cliente:

var httpBinding = new WSHttpBinding(SecurityMode.Message); 
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate; 
httpBinding.Security.Message.NegotiateServiceCredential = false; 
httpBinding.Security.Message.EstablishSecurityContext = false; 
var httpUri = new Uri("http://serviceaddress"); 
var httpEndpoint = new EndpointAddress(httpUri, EndpointIdentity.CreateDnsIdentity("name of server cert")); 
var newFactory = new ChannelFactory<IMetaService>(httpBinding, httpEndpoint); 
newFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, "client certificate thumbprint"); 
newFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, "server certificate thumbprint"); 
var channel = newFactory.CreateChannel(); 
+1

Gracias por responder a su propia pregunta y la disponibilidad para este código único enfoque. Parece que mucha gente lucha para lograr esto, así que puedo señalarles esta pregunta en el futuro. –

Cuestiones relacionadas