Enabling SSL for a WCF Service

January 30, 2012

Introduction

Last week a reader mailed me with some questions about my “WCF over HTTPS” blog post, which I wrote almost 3 years ago.

I created some sample code to help him enable SSL for a WCF service. Last year this was my most popular article, so I thought it would make sense to create a new up-to-date version that shows you step-by-step how to enable SSL for a WCF service with as little fuss as possible.

Let’s get started…

Table Of Contents

Step 1 – The Service

First we are going to create a simple and easy-to-use WCF service. Start up Visual Studio 2010 and create a new blank solution called “SslEnabledWcfService”. Next add a new class library project to it called “CustomerService”.

Solution Explorer

Add a reference to the System.ServiceModel and System.Runtime.Serialization assemblies to the CustomerService project.

Add a new interface called ICustomerService to the project
that defines the service contract.

[ServiceContract]
public interface ICustomerService
{
    [OperationContract]
    IEnumerable<Customer> GetCustomers();
}

The service returns a collection of customers. Each customer is represented by an instance of the Customer class.

[DataContract]
public class Customer
{
    [DataMember]
    public Guid Id { get; set; }

    [DataMember]
    public string FirstName { get; set; }

    [DataMember]
    public string LastName { get; set; }
}

Go ahead and add a file called Customer.cs. Copy and paste the code listed above.

The actual service implementation is very simple. It returns a list of customers which I create on the fly. No use in dealing with a database, or another persistant data store for this post. Let’s keep things as simple as possible.

[ServiceBehavior]
public class CustomerService : ICustomerService
{
    private IEnumerable<Customer> LoadCustomers()
    {
        //...
    }

    public IEnumerable<Customer> GetCustomers()
    {
        var customers = new List<Customer>();
        customers.AddRange(LoadCustomers());
        return customers;
    }
}

Check out the source code accompanying this post for the full code of the CustomerService class.

Top of page

Step 2 – Configuration

OK, now it’s time to add some configuration for our service. The host process (IIS) needs this to be able to figure out how to host the service. First add a new application configuration file called Web.config to the CustomerService project.

Solution Explorer

First you need to list the service in the <system.serviceModel> node.

<system.serviceModel>
  <services>
    <service name="CustomerService.CustomerService" 
              behaviorConfiguration="MyServiceBehavior">
        
      <endpoint address="" 
                binding="basicHttpBinding"
                bindingConfiguration="TransportSecurity" 
                contract="CustomerService.ICustomerService" />
        
      <endpoint address="mex"
                binding="mexHttpsBinding"
                contract="IMetadataExchange" />      
    </service>
  </services>
    
  <!--...-->
</system.serviceModel>

As you can see the service is linked to a custom service behavior called “MyServiceBehavior”. You need to define this behavior in the <behaviors> node of the <system.serviceModel> node.

<behaviors>
  <serviceBehaviors>
    <behavior name="MyServiceBehavior">
      <serviceMetadata httpsGetEnabled="true" httpsGetUrl="" />
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>      
</behaviors>

Note that the httpsGetEnabled property of the behavior is set to true. This allows us to retrieve metadata for the service using an HTTPS/GET request. Handy for creating our client proxies later on.

The first endpoint (non-mex) of the service is also tied to a custom binding (basicHttpBinding) called TransportSecurity.

<bindings>
    <basicHttpBinding>
      <binding name="TransportSecurity">
        <security mode="Transport">
          <transport clientCredentialType="None" />
        </security>
      </binding>
    </basicHttpBinding>
</bindings>          

It is on the binding level that you must specify which security model the service uses. Here we set the mode to Transport (SSL) and turn off any type of client authentication.

Top of page

Step 3 – Hosting The Service

The service has been created and configured. Time to host it. I’m using IIS 7.5 (7.5.7600.16385) on Windows 7 for this purpose. Create a new text file called “Service.svc”. Note the .svc extension!

Add it to the CustomerService project.

Solution Explorer

It only contains one line, namely:

<%@ ServiceHost Language="C#"
                Service="CustomerService.CustomerService" 
                CodeBehind="CustomerService.cs" %>

Here you identify the service, the language used and the location of the code behind file.

Open up Windows Explorer and navigate to the default installation folder for IIS (C:\inetpub). I started with a clean installation to make things easy. Since I don’t host any other sites locally I deleted everything I found within the wwwroot subfolder. You might want to create a subfolder within the wwwroot folder to host your service. Once you have done so create a new directory called bin within the wwwroot folder or your custom subfolder.

To host the service you must copy the following files to the directory in which you host your service:

  • Service.svc
  • Web.config
  • CustomerService.dll (\bin)

You must copy the compiled CustomerService.dll assembly (and any other dependent assemblies) inside the bin folder! Just set your solution configuration to Release, rebuild your solution and copy the necessary files as described.

Inetpub wwwroot

Almost there, we just need to configure IIS. Start up the Internet Information Services (IIS) Manager and navigate to the Default Web Site node in the left pane.

IIS Manager

Double click on the Default Document displayed in the middle pane under the IIS group.

Default Document

Remove all the documents listed there and afterwards add a new document called Service.svc. When we navigate to http://localhost we want IIS to serve up the Service.svc document by default.

Default Document

Open your favorite browser (*cough* Chrome * cough*) and navigate to http://localhost. You’ll be greeted by the following error page:

Secured Page

The page is secured and cannot be accessed via http. Exactly what we want! You can try and access it via https://localhost, but this will result in a page not found error as we have not yet configured SSL.

Top of page

Step 4 – SSL Certificate

Before you can configure your service to use SSL you need a valid SSL certificate. Luckily you can create one yourself for development / testing purposes instead of purchasing one. Using the makecert.exe command-line utility you can create your own certificates.

Let’s quickly create a certificate. Start up an elevated Visual Studio Command Prompt and enter the following command:

makecert -r -pe -n “CN=YourComputerName” -b 01/01/2012 -e 01/01/2020
-eku 1.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -sp
“Microsoft RSA SChannel Cryptographic Provider” -sy 12

Make sure to replace the term “YourComputerName” with your actual computer’s name. After executing the command you should get a simple “succeeded” message.

Makecert.exe

Top of page

Step 5 – Enable SSL

Alright, we have our SSL certificate. Let’s bind it to our service. Go back to IIS Manager and select the Default Web Site node. In the right pane click on the “Bindings…” link.

Bindings

In the Site Bindings popup click on the Add button to add a new binding.

Site Bindings

and enter the following data to enable SSL for your site:

Site Binding

Be sure to select the SSL certificate you created earlier! Just click OK to add the binding and close the Site Bindings popup afterwards.

Restart your web site and navigate to https://localhost. This time it’ll work, but you’ll probably get a warning message because of your untrusted SSL certificate. Just ignore it.

SSL Enabled Service

Top of page

Step 6 – Consume The Service

Now that we have our service running in IIS and secured with SSL let’s test it. Time to consume the service. Add a new console application to the solution called ClientApp. Add a service reference to our newly created WCF service.

Add Service Reference

When adding the service reference Visual Studio will report a problem with the SSL certificate.

Certificate Problem

Just click Yes to proceed. The message is shown because the certificate has not been issued by a company you have chosen to trust.

After you’ve created the service reference you can consume the service. Let’s display a list of the customers.

using (var proxy = new CustomerServiceClient())
{
    var customers = proxy.GetCustomers();
    foreach(var customer in customers)
    {
        Console.WriteLine(String.Format("{0} {1}", customer.FirstName, customer.LastName));
    }
}

When you try to execute this code you’ll get the following exception:

SecurityNegotiatianException

The client application does not trust the service. You can fix this by inspecting the certificate which the service hands over to the client. You need to hook up a handler for the ServicePointManager’s ServerCertifcateValidationCallback.

ServicePointManager.ServerCertificateValidationCallback += customXertificateValidation;

When this callback is triggered you can inspect the server certificate.

private static bool customXertificateValidation(object sender, X509Certificate cert,
    X509Chain chain, SslPolicyErrors error)
{
    var certificate = (X509Certificate2) cert;

    // Inspect the server certficiate here to validate 
    // that you are dealing with the correct server.
    // If so return true, if not return false.
    return true;
}

We’re finally there. If you run the client application now it will correctly list the customers returned by the SSL-enabled WCF service.

The Customers

You can download the source code accompanying this article from the download page. If you have any questions or suggestions please drop me an e-mail or submit a comment.

Top of page

14 Responses to “Enabling SSL for a WCF Service”


  1. […] Enabling SSL for a WCF Service (Christophe Geers) […]


  2. […] Enabling SSL for a WCF Service ** […]

  3. Dac Says:

    hello
    Why if I put clientCredentialType=”Certificate” nothing is working

    Thanks
    Dac

    • Christophe Says:

      This article is about configuring your service so that all communication with it is done privately over HTTPS. By setting the clientCredentialType to Certifcate you require that the client , the app that calls the service, authenticates itself using X.509 certificate. You need to make sure that:

      * The clients sends the service a certificate
      * Your service verifies the client certificate and authenticates the client.

  4. Lisbeth Says:

    I am trying for clientCredentialType=”Certificate”. I could find over net that the SSL settings need to be enabled to require client certificate. What does the Require SSL in SSL settings imply? When i have enabled the Require SSL setting and client certificate require option . And now i cant get my service up!

  5. vicente Says:

    But the site still working with http……i have iis 5.1

  6. Rob Says:

    hi, how i can expose my WCF service when i’m using wsHttpBinding, because i need to use the transaction but also i need to use SSL certificate

  7. piotr Says:

    Hi Christophe, I tried to do step by step your tutorial, i even download the example app, but in your app and in my app i get the same error:

    at var customers = proxy.GetCustomers();

    i get FaulException was unhandled
    The server was unable to process the request due to an internal error….

  8. Claudio Says:

    Hi,trying this tutorial (thanks btw) in a clean virtual machine.
    At step3 when it’s supposed to give me the 403.4 (SSL needed) it instead gives me the service.svc content in clear. Any ideas why?

  9. Alexander Says:

    Thanks for article, it’s very helpful. Special thanks for source codes in archive!

  10. William Says:

    Thanks


Comments are closed.

%d bloggers like this: