7

The Background:

I have a Service hosted on IIS 7.0 behind a Load Balancer which decrypts SSL as traffic passes through it.

The security mode required of the Service is Mixed-Mode ie TransportWithMessageSecurity

To enable the Service to accept HTTP traffic whilst allowing clients to communicate to the Load Balancer over SSL, I have created a User Defined Binding, which adds a custom HttpTransportBindingElement to its Channel Stack.

The custom HttpTransportBindingElement in turn asserts to the framework that it is capable of Encrypting and Signing messages...therefore the Framework won't complain when traffic comes in through it via HTTP because the Transport is claiming that it is signing/encrypting the messages...even though its not.

(For all those concerned, this has been determined to be acceptable security wise because the message orginally should have arrived over SSL to the Load Balancer...)

The Problem:

When we use svcutil.exe to generate the client proxy, the resulting auto-generated app.config file contains an endpoint to the service which is addressed over HTTP. This should be over HTTPS.

Additionally the <transport> element within the <customBinding> node is defined as a <httpTransport> element when it needs to be a <httpsTransport> element.

I suspect this is because the WSDL which is generated by the framework on the server, is being built with HTTP addresses instead of HTTPS > in turn, as a result of using the custom HttpTransportBindingElement (as explained above).

The auto-generated app.config for the client:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
    <bindings>
        <customBinding>
            <binding name="myBindingEndpoint">
                <!--    WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'http://tempuri.org/':    -->
                <!--    <wsdl:binding name='myBindingEndpoint'>    -->
                <!--        <sp:HttpToken xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:HttpToken>    -->
                <security defaultAlgorithmSuite="Default" authenticationMode="CertificateOverTransport"
                    requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"
                    keyEntropyMode="CombinedEntropy" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
                    <localClientSettings cacheCookies="true" detectReplays="false"
                        replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
                        replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
                        sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
                        timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
                    <localServiceSettings detectReplays="false" issuedCookieLifetime="10:00:00"
                        maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
                        negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
                        sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
                        reconnectTransportOnFailure="true" maxPendingSessions="128"
                        maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
                    <secureConversationBootstrap />
                </security>
                <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
                    messageVersion="Default" writeEncoding="utf-8">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                </textMessageEncoding>
                <httpTransport manualAddressing="false" maxBufferPoolSize="524288"
                    maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
                    bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
                    keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
                    realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
                    useDefaultWebProxy="true" />
            </binding>
        </customBinding>
    </bindings>
    <client>
        <endpoint address="http://myserver/GAEASSLWcfService/ServiceOverSSL.svc"
            binding="customBinding" bindingConfiguration="myBindingEndpoint"
            contract="IServiceOverSSL" name="myBindingEndpoint" />
    </client>
</system.serviceModel>
</configuration>

The Work-around:

Simply changing the <httpTransport /> to <httpsTransport /> and re-addressing the endpoints to use HTTPS fixes the issue.

But we'd prefer to not have to instruct our service consumers to change their .config files...the use of our service should be as seemless as possible...

The Question:

How can i ensure the client proxies will generate automatically with the correct Addresses and Transport elements???

References: For those who want to learn about the solution to the 'service behind a load-balancer/ssl decrypter' and the custom HttpTransportBindingElement, see this post XXX by ZZZ regarding building the user defined binding and also this post XXX by ZZZ regarding some of the other issues with exposing Services behind a Load Balancing/SSL accelerator.

JTech
  • 3,420
  • 7
  • 44
  • 51

2 Answers2

3

I was having the same problem, my WSDL was generated with the http scheme instead of https behind my load balancer.

I've reflected the WCF code and I found a solution that worked, for me though.

In addition to useRequestHeadersForMetadataAddress, you need to turn httpGetEnabled off and httpsGetEnabled on in the serviceMetadata.

Also, if you're using .net 4 like I think you are, instead of adding a custom HttpTransportBindingElement, just use the standard HttpTransportBindingElement and set AllowInsecureTransport on your TransportSecurityBindingElement.

Sebastien
  • 570
  • 3
  • 5
  • 18
  • Hi Sebastien, thanks for contributing. I've long since moved on from this project so am unable to check whether your answer solves my problem. But i'll +1 you for your efforts... – JTech Apr 11 '13 at 11:54
  • No problem, thanks thogh. Also, to be able to use the service behind a load balancer you need to configure a listen uri on the endpoint in addition of an address. Client side, you need to use a ClientViaBehavior on the endpoint with the given listen uri. This will fix the AddressFilter mismatch error. – Sebastien Apr 11 '13 at 13:21
  • I had the exact same problem as @JTech and the above answer corrected the problem. The only problem is that after making this modification the WSDL links no longer work. I can still add a reference to my service in Visual Studio via ...Service.cs/mex but I would like the WSDL to resolve. – dparsons Jan 12 '16 at 19:35
0

Check out this question. Try to configure:

<serviceBehaviors>
   <behavior name="<name>">
     <!-- Other options would go here -->
     <useRequestHeadersForMetadataAddress>
       <defaultPorts> <!-- Use your own port numbers -->
          <add scheme="http" port="81" />
          <add scheme="https" port="444" />
        </defaultPorts>
      </useRequestHeadersForMetadataAddress>
   </behavior>
</serviceBehaviors>
Community
  • 1
  • 1
Yaron Naveh
  • 23,560
  • 32
  • 103
  • 158
  • I have read about this but figured it didn't apply as I am using .Net 4 and this fix is for prior versions. However, I did try it anyway, and it appears to make no difference. Even browsing to the WSDL over HTTPS still results in HTTP addressing...if i go to HTTPS //mydomain/GAEASSLWcfService/ServiceOverSSL.svc?wsdl code i get references like: HTTP //mydomain/GAEASSLWcfService/ServiceOverSSL.svc?xsd=xsd0 – JTech Jun 06 '12 at 08:58