Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect a WCF service to an HTTPS endpoint with Windows credential

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>
like image 552
Uriah Blatherwick Avatar asked Mar 14 '12 17:03

Uriah Blatherwick


1 Answers

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.

like image 93
Joe Strommen Avatar answered Nov 15 '22 11:11

Joe Strommen