6

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>
Community
  • 1
  • 1
  • Possible duplicate of [Why would WCF fail to call a SOAP service when a 302 response is encountered?](http://stackoverflow.com/questions/17152385/why-would-wcf-fail-to-call-a-soap-service-when-a-302-response-is-encountered) – Luizgrs Oct 08 '15 at 20:12

2 Answers2

1

I just did something similar and I can confirm that this doesn't work. What is even worse it is probably not possible to change without replacing default WCF HTTP transport implementation.

Both redirection and authentication is handled directly inside WCF's HTTP processing which is internal. You cannot handle redirection manually which cause problem if you get 301 Moved permanently and WCF doesn't use your configured client credentials after redirection.

The problem with sending GET instead of POST after redirection should be theoretically solved by returning 307 Temporary redirect instead of 302 Found.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I'm pretty sure we tried this and WCF didn't understand the response. I'm hoping there are ways to deal with this in 4.5 but I haven't looked into it yet. – Uriah Blatherwick May 31 '12 at 12:43
1

I can't figure out why this is a GET and not a POST

That is the cause of your problem. After receiving a 302 response to a POST, it is expected behavior for a client to GET the new URL. See the following at http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

Also, the following SO post has some good info: Response.Redirect with POST instead of Get?

So WCF is doing what it should do by refusing to re-POST after a 302 redirect. Unfortunately I'm not sure what can be done to resolve your problem, other than specifying the protocol correctly the first time to avoid the 302.

Community
  • 1
  • 1
Joe Strommen
  • 1,236
  • 10
  • 18
  • That definitely explains the GET, but it seems like WCF should be able to handle this switch. Perhaps in its internals WCF only sends creds on a post? Like maybe that portion of the framework isn't implemented properly? Some way to know for sure would be great. – Uriah Blatherwick Mar 14 '12 at 18:34
  • Does the 401 Unauthorized include the appropriate WWW-Authenticate headers? – Joe Strommen Mar 14 '12 at 19:49
  • both 401s (with the redirect and without the redirect are identical. – Uriah Blatherwick Mar 14 '12 at 20:00