WCF Client: First call fails, second call succeeds

て烟熏妆下的殇ゞ 提交于 2020-12-06 06:41:23

问题


I have a REST webservice which calls an external SOAP webservice using a WCF client. This REST webservice is hosted in IIS on our test environment.

When calling the REST webservice, which then calls the external webservice (using the WCF client), after the REST webservice has been restarted in IIS the first call by the WCF client throws a SecurityNegotiationException. The second call to the REST webservice, and indirectly and all subsequent calls succeed.

To illustrate this, here's an image:

This SecurityNegotiationException is as follows:

System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'X'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.

The endpoint and binding are as follows (generated by adding service reference, modified the customBinding slightly):

<endpoint address="https://..." binding="customBinding" bindingConfiguration="MyBinding" contract="WS_..." name="MyEndpoint" />
...
<customBinding>
    <binding name="MyBinding">
      <textMessageEncoding messageVersion="Soap11" />
      <security authenticationMode="UserNameOverTransport" />
      <httpsTransport requireClientCertificate="true" />
    </binding>
</customBinding>

The code that calls the external webservice:

MyEndpointClient client = new MyEndpointClient("MyEndpoint");
client.ClientCredentials.UserName.UserName = authInfo.Username;
client.ClientCredentials.UserName.Password = authInfo.Password;
client.ClientCredentials.ClientCertificate.Certificate = authInfo.Certificate;
var result = client.requestInformation(parameters); // This fails the first time after IIS restart.

authInfo.Certificate is being loaded as follows:

authInfo.Certificate = new X509Certificate2(certificateBytes, certificatePassword);

Some more information:

  • Calling the external service using the WCF client works fine the first time (and all subsequent calls) when I run the REST webservice local.
  • I've added the SOAP webservice WSDL to the project by adding a service reference.
  • This webservice requires a username and password in combination with a certificate. WSE3.0 (Windows Security Extensions) must be used, I cannot use WSE2.0.
  • The certificate loads correctly in every case, I've surrounded creating the X509Certificate2 using a try-catch which catches a CryptographicException and cancels further processing in the REST-webservice (call to SOAP webservice does not get executed). I've verified that the certificate which I'm testing with is valid.
  • When adding the external SOAP webservice WSDL, it generates a custom binding (so not a basicHttpBinding or WsHttpBinding which I've manually tried).
  • The external SOAP webservice supports TLS 1.0, 1.1 and 1.2 (tested using SSLLabs).
  • The webservice runs with administrator rights on the test environment.
  • IIS on the test environment runs on version 8.5.9600.16384 on Windows Server 2012 R2 Standard

What I've tried and did not fix the problem:

  • Calling the SOAP webservice a second time (and more, up to 10 times) after the first time, in the same lifecycle of the REST-call (duplicated the line client.RequestInformation(parameters))
  • Creating a new MyEndpointClient after the first failing call, and executing a call with the new client.
  • Loading the certificate from the certificate store
  • Loading the certificate from a file, per recommendation from this blogpost (see tip 5)
  • Using WsHttpBinding or BasicHttpBinding
  • Using different authenticationMode on the security> tag in a customBinding.
  • Using localClientSettings reconnectTransportOnFailure="true" /> in the security> tag
  • Setting System.Net.ServicePointManager.Expect100Continue = true;
  • Setting System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; (also tried TLS 1.0 and 1.1 as well as Tls10 | Tls11 | Tls12 at once)
  • Setting System.Net.ServicePointManager.ServerCertificateValidationCallback += (a,b,c,d) => true; (not a good idea, but was worth a try)
  • Setting client.ClientCredentials.UseIdentityConfiguration = false; (also using Web.config configuration using behaviors)
  • Setting client.ClientCredentials.SupportInteractive = false; (also using Web.config configuration using behaviors)

Any ideas to get the first call to the SOAP webservice working as stable as the next calls?


回答1:


For some reason this only occurred on one test server, and not other servers. A trace log of the call to the external SOAP webservice showed that the internal function AcquireCredentialsHandle failed with error code 0X8009030D.

After some more investigation I found several certificates (from the external SOAP webservice) that were installed on the server in question. They seemed to be conflicting with the call to the external SOAP webservice. After deleting these certificates, the first call now succeeds!

Update: I encountered the same problem again, but now on my development machine. Cleaning certificates did not help, and all requests failed with the same SecurityNegotiationException. To fix this, I've added a pass-through for HTTP 100 status codes, and forced the connection to TLS 1.2:

ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Note that I added this code before I initialised the WCF Client (MyEndpointClient in the question's post), to make sure the WCF Client uses these settings.



来源:https://stackoverflow.com/questions/50249826/wcf-client-first-call-fails-second-call-succeeds

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!