使用证书进行程序化WCF消息安全性配置

9
我编写了一个使用WSHttpBindings的自托管WCF服务,并尝试使用我自己生成的证书实现消息级安全性。不幸的是,我通过Service Trace Viewer获得了一个 buried exception,指出“未能识别提供给该包的凭据”。
一些注意事项: 1. 这必须在代码中完成,而不是在配置中。 2. (Server/Client)Cert是存储在本地计算机存储区中的证书,在调试时我的用户可以访问私钥。 3. 我已经谷歌了这个问题并找到了一个很好的资源来设置WCF基于消息的安全性here 我不确定我漏掉了什么。大部分东西似乎很简单,除了创建端点标识。无论我是使用DnsEndpointIdentities、基于证书的端点标识还是根本没有标识,它都以相同的消息失败。
有人能指点我正确的方向吗?
服务器端:
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();

客户端:
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();
1个回答

12

这篇MSDN文章非常有帮助。我认为问题的根源在于将以下消息安全参数设置为false:

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

现在服务器端的总体代码看起来更像:

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

还有客户端:

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
感谢您回答自己的问题并提供这种代码方法。似乎很多人都难以实现这一点,所以我将来可以向他们指出这个问题。 - Sixto Saez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接