SSL offloading in load balancer scenario
Problem description
WCF service hosted on IIS runs over http behind load balanced servers. The load balancer is configured to perform ssl offloading.
The WCF service is perfectly browsed on the server box over http. The same service is also browsed properly without any issues at the client side. When we consume the wsdl and hit the service request using any tool, there was no response from the service.
Client(https) --->>>> LoadBalancer ---->>>> Service(http)
Issue
The only issue is with metadata. When we take a peek at the address in the SOAP:Address, it still used to point to http address for the https wsdl.
Service URL: https://www.myserver.com/Service/TestService.svc?wsdl
And, its wsdl looks like the following:
<wsdl:service name="TestService">
<wsdl:port name="BasicHttpBinding_ITestService" binding="tns:BasicHttpBinding_ITestService">
<soap:address location="<www.myserver.com/Service/TestService.svc>" />
</wsdl:port>
</wsdl:service>
This means though the client tries to access the service over https, it still gets redirected to http because of soap:address location.
Approach 1
Use the following cusotmBinding in service web.config:
<customBinding>
<binding name="serviceBinding">
<textMessageEncoding>
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" />
</textMessageEncoding>
<security allowInsecureTransport="true" enableUnsecuredResponse="true">
<secureConversationBootstrap requireDerivedKeys="false" />
</security>
<httpTransport maxReceivedMessageSize ="2147483647" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
If enableUnsecuredResponse value set to true, the following new features are enabled in WCF:
- WCF clients can accept unsecured responses even if the outgoing messages are secured by using the Secure Socket Layer (SSL) protocol to sign the message body.
- WCF services can send unsecured responses that have no security header in SOAP envelopes even if the request is secured.
Reference: support.microsoft.com/kb/971493
If allowInsecureTransport value set to true, Mixed-Mode security binding with http as the transport is allowed instead of the secure https option.
If requireDerivedKeys value set to false, it will specify the keys won’t be derived from the original proof keys.
Other values are just set to the highest values, because we had to accommodate large data transfer too.
In order to test on the client,
- Take a console application
- Add service reference
- Modify app.config binding to use the same customBinding as of service web.config
- The test will be successful
Approach 2
Another alternative is to modify the wsdl completely, and make it available over https on the service side.
This involves modifying the wsdl location to point to a virtual directory and state explicitly that metadataLocation is modified to the virtual directory instead of the actual schema.
How can we make it?
Create a folder named Metadata.
Download metadata by visual studio command prompt:
>svcutil /t:metadata https://www.myserver.com/Service/TestService.svc?wsdl
It will download a list of xsd and wsdl files.
Let us target wsdl files first and then the xsd files in order to modify namespace and schmeLocation to point out to https.
singleWsdl
- Modify xmlns:tns and targetNamespace to https://www.myserver.com/Service inside <wsdl:definitions>
- Modify targetNamespace to https://www.myserver.com/Service/Imports inside <wsdl:types> <xsd:schema>
- Modify schemaLocation to https://www.myserver.com/Service/XsdFile1.xsd and namespace to https://www.myserver.com/Service inside <wsdl:types> <xsd:schema> <xsd:import>. Follow the similar steps for the rest of imports
- Modify namespace reference to https inside <wsdl:message> <wsdl:part>
- Modify action to https inside <wsdl:portType> <wsdl:operation> for <wsdl:input> and <wsdl:output>
Wsdl
- Identify custom namespaces, modify namespace links to https. Ensure xmls:tns and targetNamespace values are same (we need not modify this)
- Modify wsdl:import to the https namespace and schema location over https to the virtual directory
- Modify soapAction to https
- Modify soapAddress location in <wsdl:service> to https URI pointing to the service file
Individual xsd files
- Modify xmlns:tns and targetNamespace values to https://www.myserver.com/Service/XsdFile1
- Basically xsd schema location would have been like ?xsd=xsd0/1… We will hard code this to certain file
- And the same approach can be followed for other xsd files
Once all the individual changes are made. These wsdl/ xsd files can be published to the IIS virtual directory. So, next time whenever the metadata request will be made – it will point to the hard coded paths in the wsdl and xsd files.
If you are publishing via visual studio, please ensure to change the Build Action for those files to Content type.
How can service make local metadata available?
Modify service behavior in the web.config as the following:
<serviceBehaviors>
<behavior name="CustomBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" externalMetadataLocation="https:// www.myserver.com/ Service /TestService.wsdl" />
</behavior>
</serviceBehaviors>
Use basciHttpBinding for simplicity sake:
<basicHttpBinding>
<binding name="BasicHttpBinding_ITestService">
<security mode="None" />
</binding>
</basicHttpBinding>
Important
- The time can only be saved if proper namespace pattern is followed while designing the contracts for your WCF service.
- The process is purely manual. Pay keen attention and modify schemaLocation and namespace to https based url (all will associate to the newly create metadata files and be available in IIS virtual directory explicitly).
- Though the service will be accessible on https, it still runs on http inside server box.
- Approach 2 is recommended in comparison in case of non-.net client (tested in case of Java client).
Created by
Purna Chandra Panda (MSFT)
Comments
Anonymous
September 15, 2015
There is also a third way, a custom WSDL export extension and this is actually what I am using. In all cases however the solution handles addressing issues but what about the binding security mode? I have services behind an offloader that have to declare the standard <security mode="None"/> in order to comply with the HTTP protocol the offloader will supply. The customer, however, requires their WSDL to declare not only HTTPS but also <security mode="Transport"><transport clientCredentialType="None" /></security>. Any ideas how to do that?Anonymous
November 02, 2015
Hi Sara, i have a similar requirement as yours and i can't seem to find a solution, did you find a solution or a work around?, i'm behind a load balancer that offloads ssl/httpsAnonymous
January 25, 2016
Hello, I have the same issue. How to approach this in case of basic authentication? Thanks for the help. Seshu