Here is the situation I am trying to deal with:
We have a WCF client that works with an http endpoint and an https endpoint but not when it is redirected (302) from http to https. We have an F5 load balancer that is performing the redirect and SSL functionality but as far as I can tell, it isn't doing anything unexpected to the requests. The redirect seems to be the culprit where WCF doesn't want to provide Windows Kerberos authentication information after the redirect is performed.
The sequence for a successful call (i.e. http with no redirect) goes like this:
- Client - Sends POST request for service with http scheme
- Server - Responds with 401 unauthorized
- Client - Sends Negotiate POST with authorization
- Server - Responds with 100 Continue
- Client - Sends soap data and completes successfully
When the call is redirected and fails it goes like this:
- Client - Sends POST request for service with http scheme
- Server - Returns 302 with redirect to https scheme for same address
- Client - Sends GET for https address (I can't figure out why this is a GET and not a POST)
- Server - Responds with 401 unauthorized
- Client - throws exception "The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'."
It is similar to this problem but not exactly the same (and there isn't really an answer there although it does reference "breaking WCF protocol" which I can find documetation on). If we turn off the F5 redirect rule http and https traffic work fine. Does WCF really not handle this simple redirect? Is there a workaround or any documentation on this flaw?
Client config (note that when testing this with https, I change TransportCredentialOnly to Transport):
<client>
<endpoint address="http://fooserver/MyService.svc/" binding="basicHttpBinding" bindingConfiguration="clientBinding" contract="Contracts.IMyService" />
</client>
<bindings>
<basicHttpBinding>
<binding name="clientBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
Server config looks like this:
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="securedBinding" contract="Contracts.IMyService">
</endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="securedBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="80" />
<add scheme="https" port="443" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>