使用basicHttpBinding时,在我的自托管WCF服务中使用带有证书的传输安全性时出错

时间:2013-05-01 08:29:11

标签: wcf x509certificate basichttpbinding

我有一个使用net.tcp的自托管WCF服务,但是现在,为了支持遗留应用程序,我们必须打开basicHttpBinding。安全性通过使用证书的传输完成,并且通过net.tcp很好地工作。该服务的配置是通过其App.config完成的:

  <system.serviceModel>
    <services>
      <service name="MyServiceHost" behaviorConfiguration="ServiceBehavior">
    <endpoint address="net.tcp://localhost:1234/MyService" binding="netTcpBinding" bindingConfiguration="CertificateCredentialsServiceBinding" name="MyService_Tcp_Certificate" contract="Wcf.MyService" />
    <endpoint address="https://localhost:2234/MyService" binding="basicHttpBinding" bindingConfiguration="HttpCertificateCredentialsServiceBinding" name="MyService_BasicHttp_Certificate" contract="Wcf.MyService" />
    <endpoint address="MyServiceMex" contract="IMetadataExchange" binding="mexTcpBinding" />
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:2235/"/>
        <add baseAddress="net.tcp://localhost:1235/" />
      </baseAddresses>
    </host>
      </service>
    </services>
    <bindings>
      <netTcpBinding>
    <binding name="CertificateCredentialsServiceBinding" receiveTimeout="00:30:00" sendTimeout="00:15:00">
      <readerQuotas maxArrayLength="2147483647" />
      <reliableSession inactivityTimeout="3.00:00:00" enabled="true" />
      <security mode="Transport">
        <transport clientCredentialType="Certificate" />
      </security>
    </binding>
      </netTcpBinding>
      <basicHttpBinding>
    <binding name="HttpCertificateCredentialsServiceBinding" receiveTimeout="00:30:00" sendTimeout="00:15:00">
      <security mode="Transport">
        <transport clientCredentialType="Certificate" />
      </security>
    </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
    <behavior name="ServiceBehavior">
      <serviceTimeouts transactionTimeout="00:15:00" />
      <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
      <serviceCredentials>
        <clientCertificate>
          <authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" trustedStoreLocation="LocalMachine" />
        </clientCertificate>
        <serviceCertificate storeLocation="LocalMachine" findValue="my-certificate-thumprint-here" x509FindType="FindByThumbprint" />
      </serviceCredentials>
    </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

当客户端使用自己的客户端证书和NET.TCP连接时,一切正常,客户端凭据正确验证。这是客户端的(简化)代码:

        MyService myService;
        Uri serviceUri = new Uri("net.tcp://localhost:1234/MyService");

        NetTcpBinding netTcpBinding = new NetTcpBinding(SecurityMode.Transport);
        netTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
        netTcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;

        Uri netTcpUri = serviceUri;
        EndpointAddress netTcpEndpoint = new EndpointAddress(netTcpUri, EndpointIdentity.CreateDnsIdentity("MyServer"));

        ChannelFactory<MyService> tempServicesFactory = null;
        ChannelFactory<MyService> servicesFactory = null;

        servicesFactory = new ChannelFactory<MyService>(netTcpBinding, netTcpEndpoint);

        servicesFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "my-client-certificate-thumprint-here");
        servicesFactory.Credentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;

        myService = servicesFactory.CreateChannel();

一直运作良好,直到这里。尝试连接到Basic Http绑定尽管失败了。这是客户端的代码:

        MyService myService;
        Uri serviceUri = new Uri("https://localhost:2234/MyService");

        BasicHttpBinding httpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
        httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

        Uri httpUri = serviceUri;
        EndpointAddress httpEndpoint = new EndpointAddress(httpUri, EndpointIdentity.CreateDnsIdentity("MyServer"));

        ChannelFactory<MyService> tempServicesFactory = null;
        ChannelFactory<MyService> servicesFactory = null;

        servicesFactory = new ChannelFactory<MyService>(httpBinding, httpEndpoint);

        servicesFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "my-client-certificate-thumprint-here");
        servicesFactory.Credentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;

        myService = servicesFactory.CreateChannel();

使用此代码,当我尝试调用服务时(在本例中为“GetAllProducts”方法),我得到以下异常:

System.ServiceModel.Security.SecurityNegotiationException was caught
  HResult=-2146233087
  Message=Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost:2234'.
  Source=mscorlib
  StackTrace:
    Server stack trace: 
       at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
       at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
       at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
    Exception rethrown at [0]: 
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at Wcf.MyService.GetAllProducts()
       at TesterApp.Initialise() in CODEFILE :line 159
  InnerException: System.Net.WebException
       HResult=-2146233079
       Message=The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
       Source=System
       StackTrace:
        at System.Net.HttpWebRequest.GetResponse()
        at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
       InnerException: System.Security.Authentication.AuthenticationException
        HResult=-2146233087
        Message=The remote certificate is invalid according to the validation procedure.
        Source=System
        StackTrace:
         at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
         at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
         at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
         at System.Net.TlsStream.CallProcessAuthentication(Object state)
         at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
         at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
         at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
         at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
         at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
         at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
         at System.Net.ConnectStream.WriteHeaders(Boolean async)
        InnerException: 

即使看起来证书无效,我确信它是有效的,因为它与NET.TCP一起使用。

哦,当然,在所有这些工作之前,我必须使用netsh.exe设置它们:

netsh.exe http add urlacl url=https://+:2234/ user=MYDOMAIN\MyUserName
netsh.exe http add sslcert ipport=0.0.0.0:2234 certhash=my-certificate-thumprint-here appid={my-service-app-guid-here}

关于问题可能是什么以及如何解决的任何想法?

谢谢!

更新

我现在设法摆脱了第一个错误,这是一个更改所有地址以匹配证书名称(MyServer)而不是使用localhost的情况。不幸的是,使用EndpointIdentity.CreateDnsIdentity("MyServer")设置DNS身份似乎不适用于HTTP绑定,即使它适用于NET.TCP。

从客户端调用服务时,我现在收到403(禁止)错误。正如您在上面的代码中看到的那样,正在设置客户端证书,但它就好像不是。如果我从我的配置(<transport clientCredentialType="Certificate" /><transport clientCredentialType="None" />中删除了期望客户端凭据类型为证书的配置,那么这一切都适用于传输安全性,但我仍然需要客户端通过客户端证书提供凭据就像NET.TCP解决方案一样。

有什么想法吗?

再次感谢!

0 个答案:

没有答案