In hell with SSL and WCF

Standard

 image

A long time ago I decided that WCF was one of those things I wouldn’t try and learn about in preference to learning other things, such as Silverlight, MVC and how to cook cookies properly.  Now that decision has come back to haunt me.

It seemed simple.  A client server prototype using wsHttpBindings and WCF.  My initial Project’s configuration files worked well on my local development machine (http).

The time came to put this on the server using SSL (https).

Much of the documentation on the web says that the simplest way of doing this is to configure IIS (IIS6 in my case) to work with SSL, then copy it over.  Words cannot express how wrong this proved to be.

For future reference, rest assured you will need very different versions of these files for local development as opposed to a production server.

I’ve also learnt that WCF gives as good as it gets in the ongoing competition between software development technologies in providing weird and useless error messages that are no hope at all in solving problems.  (Although handy for doing google searches to find others as miserable as you are)

Before

image

My original (Visual Studio generated) client app.config file looked like this:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="WSHttpBinding_IClientConnect" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
          maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
          allowCookies="false">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
        <reliableSession ordered="true" inactivityTimeout="00:10:00"
            enabled="false" />
        <security mode="Message">
          <transport clientCredentialType="Windows" proxyCredentialType="None"
              realm="" />
          <message clientCredentialType="Windows" negotiateServiceCredential="true"
              algorithmSuite="Default" />
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
  <client>
    <endpoint address="http://localhost:10916/SecureClientDemoServer/ClientConnect.svc"
        binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IClientConnect"
        contract="ClientService.IClientConnect" name="WSHttpBinding_IClientConnect">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
  </client>
</system.serviceModel>

My server web.config file looked like this:

    <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <services>
   <service behaviorConfiguration="ServiceBehavior" name="ClientConnect">
    <endpoint address="" binding="wsHttpBinding" contract="IClientConnect">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
   </service>
  </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>
                    <serviceMetadata httpGetEnabled="true"/>
                    <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>

 

After

 image

app.config

<system.serviceModel>
   <bindings>
    <wsHttpBinding>
      <binding name="WSHttpBinding_IClientConnect" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
        <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
        <security mode="Transport">
          <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
          <message clientCredentialType="None"  algorithmSuite="Default" negotiateServiceCredential="false" establishSecurityContext="false" /> 
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
  <client>
    <endpoint address=https://remoteserver/SecureClientDemo/ClientConnect.svc binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IClientConnect" contract="ClientService.IClientConnect" name="WSHttpBinding_IClientConnect">
    </endpoint>
  </client>
</system.serviceModel>

 

web.config

    <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        <services>
            <service behaviorConfiguration="ServiceBehavior" name="ClientConnect">
                     <endpoint address=https://remoteserver/SecureClientDemo/ClientConnect.svc bindingConfiguration="HttpsBinding" binding="wsHttpBinding" contract="IClientConnect">
                </endpoint>
                <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"
                                 name="MexHttpsBindingEndpoint" 
                                 />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="ServiceBehavior">
                    <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>
                    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
                    <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
           <bindings>
         <wsHttpBinding>
          <binding name="HttpsBinding">
            <security mode="Transport">
              <transport clientCredentialType="None"/>
            </security>
          </binding>
        </wsHttpBinding>
            </bindings>
    </system.serviceModel>

 

 

Conclusion

This article is intended to show on the web a working set of configuration parameters, so for the time being I don’t have time to go into and explanation I only half understand.  I hope people find this helpful.

 

Links

http://msdn.microsoft.com/en-us/library/ms729700.aspx

http://stackoverflow.com/questions/1521117/wcf-over-ssl-404-error

http://stackoverflow.com/questions/2435823/the-provided-uri-scheme-https-is-invalid-expected-http-parameter-name-via

http://msdn.microsoft.com/en-us/library/ff648840.aspx

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s