Exploring all things .NET and beyond...

Creating a WCF RESTful Service And Secure It Using HTTPS Over SSL

Well I have had a few posts now on security, and focused some specifically on HTTPS and WCF. One of the most popular types of services we can create using WCF are RESTful services. The REST architecture and RESTful services have become so popular due to their inherent flexibility and being more consumer and platform agnostic as opposed to their WCF SOAP WS-* counterparts. However with this popularity and quickly expanding use we must not forget about securing our RESTful services especially when exposing them for wide use on the internet. Since REST services communicate over HTTP, we can leverage our existing knowledge and security principals we use for traditional websites that communicate over HTTP.

I wanted to highlight a few options for securing and authenticating to RESTful services using WCF in some upcoming posts. This 1st one will speak to securing the pipeline that REST services communicate over which is HTTP.

As we all know (or if not, now you do!) you can secure the communication over HTTP by using a SSL certificate. This is the 1st step in securing the data being communicated from the client and our RESTful service. Let's begin by looking at our simple ServiceContract. It contains a GET method defined with a CLR name of 'GetCustomerData' being exposed as the noun 'Customer' to adhere to REST architecture standards:

namespace RESTfulSecuritySH
{
   [ServiceContract]
   public interface ISecureRESTSvcTest
   {

     [OperationContract]
     [WebInvoke(Method = "GET",
                ResponseFormat = WebMessageFormat.Json,
                UriTemplate = "/Customer/{CustID}")]
     Customer GetCustomerData(string CustID);
   }
}

Behind the scenes the implemented code is returning the ID provided along a 'Customer' data contract with a some fake customer data. Obviously in a real implementation we would be connecting to a data repository to get this information, but for this example we will just hardcode values to be returned as security is the focus here and not the service implementation details.

namespace RESTfulSecuritySH
{
  public class SecureRESTSvcTest : ISecureRESTSvcTest
  {
     public Customer GetCustomerData(string CustID)
     {

        Customer customer = new Customer()
        {
          ID = CustID,
          FirstName = "John",
          LastName = "Smithers",
          PhoneNumber = "800-555-5555",
          DOB = "01/01/70",
          Email = "jsmithers@fancydomain.com",
          AccountNumber = "1234567890"
        };

        return customer;
     }
  }

  [DataContract]
  public class Customer
  {
     [DataMember]
     public string FirstName { get; set; }
     [DataMember]
     public string LastName { get; set; }
     [DataMember]
     public string PhoneNumber { get; set; }
     [DataMember]
     public string DOB { get; set; }
     [DataMember]
     public string Email { get; set; }
     [DataMember]
     public string ID { get; set; }
     [DataMember]
     public string AccountNumber { get; set; }
  }
}

The default configuration for this service uses the webHttpBinding as required for RESTful services created using WCF. This configuration is for a self-hosted service as it provides a *baseAddress* value. This identical configuration could be used for an IIS hosted service. Just keep in mind the *baseAddress* will be ignored and replaced by the virtual directory structure set up in IIS.

<system.serviceModel>
  <services>
    <service behaviorConfiguration="SecureRESTSvcTestBehavior" name="RESTfulSecuritySH.SecureRESTSvcTest">
        
      <host>
        <baseAddresses>
          <add baseAddress="http://DevMachine1234:8099/MyRESTServices/"/>
        </baseAddresses>
      </host>

      <!--webHttpBinding allows exposing service methods in a RESTful manner-->
      <endpoint address=""
        binding="webHttpBinding"
        behaviorConfiguration="webHttpBehavior"
        contract="RESTfulSecuritySH.ISecureRESTSvcTest" />

      <endpoint address="mex"
        binding="mexHttpBinding"
        contract="IMetadataExchange" />

    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="SecureRESTSvcTestBehavior">
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="false"/>
      </behavior>
    </serviceBehaviors>

    <!--Required default endpoint behavior when using webHttpBinding-->
    <endpointBehaviors>
      <behavior name="webHttpBehavior">
        <webHttp/>
      </behavior>
    </endpointBehaviors>

  </behaviors>

</system.serviceModel>

At this point if we start our service using the WCF Test Client (if trying this locally), and then call the RESTful URI http://DevMachine1234:8099/MyRESTServices/Customer/8 to our service, you will get the JSON output (below) as expected (use Chrome, FF, or Safari to test. IE and Opera make you open a separate file). 'DevMachine1234' is the name of my dev box and eventually will be the name that needs to match up with the one provided to the SSL certificate which we will discuss in a moment.

{"AccountNumber":"1234567890","DOB":"01\/01\/70","Email":"jsmithers@fancydomain.com","FirstName":"John","ID":"8","LastName":"Smithers","PhoneNumber":"800-555-5555"}

OK, simple enough but notice there is data here that really is sensitive. The structure and design of our Customer data contract is not the focus of this post and is a flattened view of example customer data, but regardless some of it is sensitive. Let's now secure the transmission of this data over HTTPS using a SSL certificate.

For this example I am going to use a self-signed certificate I created locally and assign it on my machine to port 8099. I have (2) posts already that explain how to do this: Create A Self-Signed SSL Certificate Using IIS 7 and Applying and Using a SSL Certificate With A Self-Hosted WCF Service.

Let's focus on the configuration changes that had to be made. Now depending on how you decide to host your WCF service there may be subtle differences in the configuration. Also I should mention here that all of the configuration can be done in code if you chose to do so. I typically prefer configuration 1st, and only rely on using code to configure and run my service if there are elements that could be different at runtime and the configuration needs the flexibility of being dynamic. If this is not the case, I lean toward configuration because of its on-the-fly configurability and ease of reading. This is one case where either method works fine.

If using IIS to host your service, the certificate can be added through the IIS Management console and applied to the site instead of using the command line netsh.exe tool for self-hosted services. The 1st configuration change is to update the base address if you are using a self-hosted service to HTTPS:

<add baseAddress="https://DevMachine1234:8099/MyRESTServices/"/>

Next we must add a bindingConfiguration value to our endpoint as shown below:

<endpoint address=""
     binding="webHttpBinding"
     bindingConfiguration="webHttpTransportSecurity"
     behaviorConfiguration="webHttpBehavior"
     contract="RESTfulSecuritySH.ISecureRESTSvcTest" />

We must also add in this new binding configuration section. If you add a bindings section at the root of the system.serviceModel section, we can configure the security to be "Transport". When using Transport security with WCF, it automatically expects we want to use HTTPS for our endpoint. There are (3) different modes in the enumeration for the security element: None, Transport, and TransportCredentialOnly. 'None' indicates there is no required security on the endpoint, 'Transport' indicates we want to secure our endpoint with a SSL certificate using HTTPS, and 'TransportCredentialOnly' provides HTTP-based client authentication only and does not provide message integrity and confidentiality. The new endpointConfiguration is below:

<bindings>
  <webHttpBinding>
    <binding name="webHttpTransportSecurity">
      <security mode="Transport" />
    </binding>
  </webHttpBinding>
</bindings>

Next within the service behavior we must enable HTTPS and disable HTTP. This way our RESTful service can only be accessed via HTTPS. This is a very important step if you intend to have your service only accessed in a secure manner. Otherwise you leave the door open to still access it via HTTP. This may be an OK scenario if hosting non-secure data that you want to be able to be accessed via HTTP or HTTPS, but otherwise it should only be one or the other.

<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>

Lastly, we need to update the metadata publishing endpoint to use HTTPS as well:

<endpoint address="mex"
  binding="mexHttpsBinding"
  contract="IMetadataExchange" />

At this point restart your service. If you encounter any errors, it is probably because the SSL certificate does not match the name of your service, the SSL cert has not been applied correctly to the port (self-hosted services only), or the all the configuration updates were not made correctly. If you completed everything successfully, you can now access your site at the following URL: https://DevMachine1234:8099/MyRESTServices/Customer/8

Now try opening a new browser and access it via HTTP; it will not work and this is what we wanted. We have now secured our RESTful service's communication.

One last big ticket item here that will set me up for my next posts on securing RESTful services has to do with the security context before and after securing our service. This will ultimately allow us to authenticate our users and move forward with security. Either debugging the RESTful call to your existing 'GetCustomer' method or from a new call that simply returns a string, try looking at the following lines of code:

//Look at the ServiceSecurityContext both using secured and non-secured service configurations:
ServiceSecurityContext svcSecurityContext;
svcSecurityContext = OperationContext.Current.ServiceSecurityContext;


Notice how if you run your service without Transport security using HTTPS, the ServiceSecurityContext instance will be 'null'. However once we secure our service, this instance will have value. Specifically if you look at the .IsAnonymous property, you will notice it is now = "true" upon securing our service.


We will work on populating this value in my next post and moving forward to authenticating the client.

Fixing The SignatureMismatchException When Updating NuGet

Recently I was trying to update the NuGet Package Manager for VS.NET 2010 from version 1.6.x to 1.7.x and ran across the following exception in the log presented when there is an error with the update process:

VSIXInstaller.SignatureMismatchException: The installed version of 'NuGet Package Manager' is signed, but the update version has an invalid signature. Therefore, Extension Manager cannot install the update. at VSIXInstaller.Common.VerifyMatchingExtensionSignatures(IInstalledExtension installedExtension, IInstallableExtension updateExtension) at VSIXInstaller.InstallProgressPage.BeginInstallVSIX(SupportedVSSKU targetAppID)
Install Error : VSIXInstaller.SignatureMismatchException: The installed version of 'NuGet Package Manager' is signed, but the update version has an invalid signature. Therefore, Extension Manager cannot install the update at. VSIXInstaller.Common.VerifyMatchingExtensionSignatures(IInstalledExtension installedExtension, IInstallableExtension updateExtension) at VSIXInstaller.InstallProgressPage.BeginInstallVSIX(SupportedVSSKU targetAppID)


The fix is simple; it requires an uninstall and reinstall. I assume updates within a version would work, but since I am actually upgrading I imagine this is what requires the uninstall 1st.

Go back to the Extension Manager and select "Installed Extensions", and then select the NuGet pacakage and press "Uninstall". Close and reopen the Extension Manager to refresh the installed packages, and search the Online Gallery for NuGet. If ordering by "Highest Ranked" it typically is the 1st or close to 1st item in the list. Now select "Download" and the installation will complete successfully.

Adding The HTML Target Schema Selection to VS.NET 2010 for HTML5 Intellisense


If you are beginning to delve into HTML5 in VS.NET say in a MVC3 project using the Razor engine for example, you will want intellisense support for HTML5. This is not difficult to do, but the 'HTML Source Editing' toolbar may not be shown by default in your VS.NET instance. To add it preform the following steps:

1. Open VS.NET but do not open any specific project. This ensures the changes you make will be for all project's opened.

2. Go to 'View -> Toolbars' and select the 'HTML Source Editing' menu item.


3. To test, open a MVC3 or MVC4 project using the Razor engine and navigate to a .cshtml view. The dropdown will now be active and the default selection will be 'XHTML 1.0 Transitional'. Change it to 'HTML5'.


4. Now try typing in the first few letters of a HTML element or attribute, like the 'Canvas' tag.


You now have the HTML5 schema validation and intellisense support.