Create Secure WCF REST API With Custom Basic Authentication

WCF REST API services are still being used by many developers for client server connectivity for data and messaging. This article is a complete guide on creating a WCF Rest service from scratch and adding security to the service using Basic Authentication. Then we’ll learn how to encrypt the basic authentication information which would be sent over the network using SSL. The main sections of this guide are the following:
  • Creating a WCF REST API service.
  • Hosting a WCF REST service in IIS from Visual studio (on local machine).
  • Deploying a WCF REST service on IIS (Local machine).
  • Adding security to the Service by using Basic Authentication.
  • Securing basic authentication credentials using SSL over Http i.e. (Https).

    1. Creating a certificate and Enabling IIS website to use Https
    2. Setting up WCF REST service to use SSL (Https)
Pre-requisite:
  • Basic knowledge of Visual studio/WCF basics.
  • Visual Studio version - 2008.
  • .NET framework - 3.5 installed.

Creating a WCF REST API service

 
To get started quickly we will use the default template of WCF service library provided in Visual Studio 2013 which I’m going to use in this guide. Follow the steps below:
  1. Launch Visual Studio 2013 (choose “Run as Administrator”, we’ll see later).

  2. From Menu File, New, then Project or click on Start Page to start a new project.

    wcf service application

  3. Let’s name it WcfWebHttpIISHostingSample. Now you’ll see a couple of files already added to the WCF Service project.

    Service

  4. Delete IService1.cs and Service1.svc file as we’ll be creating new files and use our code to host the service via ServiceHostFactory class.

  5. Add a new interface ITestService by right clicking on project and Add new item. Select Interface and rename it to ITestService. Copy the following code and add it to newly created interface.
    1. namespace WcfWebHttpIISHostingSample  
    2. {  
    3.     [ServiceContract]  
    4.     public interface ITestService  
    5.     {  
    6.         [WebInvoke(Method = "GET", UriTemplate = "/Data/{data}")]  
    7.         string GetData(string data);  
    8.     }  
    9. }  
    In above interface we have added WebInvoke attribute though we can also use WebGet, it would not make any difference. I’ll stick with WebInvoke as it supports POST, PUT, DELETE http verbs as well.

  6. Add a new class TestService which will implement the above declared interface.
    1. using System.ServiceModel;  
    2. using System.ServiceModel.Web;  
    3. using System.Web;  
    4.   
    5. namespace WcfWebHttpIISHostingSample  
    6. {  
    7.     [ServiceContract]  
    8.     public interface ITestService  
    9.     {  
    10.         [WebInvoke(Method = "GET", UriTemplate = "/Data/{data}")]  
    11.         string GetData(string data);  
    12.     }  
    13. }  
  7. We have defined a service contract, a Rest method with a sample definition. Now we have to define its end points. To add end point simply copy the followings settings and paste it into your configuration file (web.config) of newly created project file under service.model tag.
    1. <system.serviceModel>  
    2.     <behaviors>  
    3.         <serviceBehaviors>  
    4.             <behavior name="ServiceBehavior">  
    5.                 <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />  
    6.                 <serviceDebug includeExceptionDetailInFaults="false" />  
    7.             </behavior>  
    8.         </serviceBehaviors>  
    9.         <endpointBehaviors>  
    10.             <behavior name="webHttpServiceBehavior">  
    11.                 <!-- Important this is the behavior that makes a normal WCF service to REST based service-->  
    12.                 <webHttp/>  
    13.             </behavior>  
    14.         </endpointBehaviors>  
    15.     </behaviors>  
    16.     <services>  
    17.         <service name="WcfWebHttpIISHostingSample.TestService" behaviorConfiguration="ServiceBehavior">  
    18.             <host>  
    19.                 <baseAddresses>  
    20.                     <add baseAddress="http://localhost/WCFRestAuthentication/api/" />  
    21.                 </baseAddresses>  
    22.             </host>  
    23.             <endpoint binding="webHttpBinding" contract="WcfWebHttpIISHostingSample.ITestService" behaviorConfiguration="webHttpServiceBehavior" />  
    24.         </service>  
    25.     </services>  
    26. </system.serviceModel>  
  8. Now we have an end point, so next we’ll add a service host factory that will host the service in IISExpress or local development server at this moment.

  9. Add new item Global.asax and add the following code in Application_Start method. You can find it under New Item, Web, then Global application Handler.
    1. protected void Application_Start(object sender, EventArgs e)  
    2. {  
    3.    RouteTable.Routes.Add(new ServiceRoute(""new WebServiceHostFactory(), typeof(TestService)));  
    4. }  
  10. Now you’ll be getting an error on ServiceRoute class in the above code. To remove this error we have to add a new reference from Add reference, Assemblies, then System.Model.Activation and the error will be gone.

  11. Now right click on Project and go to Properties. In properties window select Web and Add a Specific Page details to map the service operation that we defined on our contract. Add Data/HelloWorldTestData in specific page setting. Here Data is your path of operation that we have defined in WebInvoke attribute and “HelloWorldTestData” is your argument that the service method will receive as an argument. Here's the screenshot:

    web

  12. Save All and Press F5.

    Save All
If you see a web page like this means you have successfully created a WCF REST service.
 

WCF REST service hosting in IIS

 
To host the above service in IIS follow the below given steps:
  1. Right click on the project and go to Properties. In properties window select Web.

  2. Now under Servers on Web settings you’ll see the following details, change the “IIS Express” to “IIS Server”.

    local iis

  3. Now Click on Create Virtual Directory. Now if you have Visual Studio running As Administrator then you’ll get a message The Virtual directory was created successfully! Otherwise you’ll receive an error message and you need to launch Visual studio again as Administrator. I mentioned it in the start of this guide.

  4. Now press F5 and your website will be up and running on IIS server instead of your IIS express.

    running on IIS server

Deploying a WCF REST service on IIS Local machine (optional)

 
You don’t actually need to deploy the current WCF service because the visual studio already using IIS server for hosting as detailed in the above step. This is just to let you know how to deploy a WCF REST service on IIS.
 
Follow the below steps:
  1. Right click on Project and go to Publish.

  2. In Publish window open the dropdown for profiles and select New Profile.

  3. Select publish method as “Web Deploy”. Enter server as “Localhost”. Add site name as “Default Web site/WcfWebHttpIISHostingSample_Demo2”. Click Validate connection, it’ll verify access rights and other information provided.

  4. Once the Validate connection succeeds click publish. You’ll get the success message in output window in Visual Studio.

  5. Test the service by entering the following url in the web browser: http://localhost/WcfWebHttpIISHostingSample_Demo2/Data/TestingDeploymentSuccess

Adding Basic authentication

 
The REST services built and run over http protocol. A simple way to enable the authentication is to use Basic Authentication (i.e. user/pwd). Basic authentication can be enabled over http protocol. Now here are the choices that we have:
 
We can use simple transport level basic authentication by using Custom username and password validator as mentioned here. But author explicitly stated that this will only work in self hosted environment. Which is not our case as we are using IIS to host our service. Also there are other methods available on the internet such as by extending ServiceAuthenticationManager or using a custom MessageInspector and use it like a custom user/pwd validator but I was not really convinced with those methods because somehow they were not the best candidate for our scenario. The challenge comes with IIS is that IIS does the authentication before WCF receives the request. And till now there’s no out of the box support for Basic Authentication for WCF REST on IIS. So we have to go with our custom solution which by extending ServiceAuthorizationManager class and override method CheckAccessCore and use it in Service Behaviors as default Authorization manager. The configuration would look something like below after setting up a custom service Authorization manager.
  1. <serviceBehaviors>  
  2.   <behavior name="ServiceBehavior">  
  3.     <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>  
  4.     <serviceDebug includeExceptionDetailInFaults="true"/>  
  5.     <serviceAuthorization   
  6.       serviceAuthorizationManagerType  
  7.         =" WcfWebHttpIISHostingSample.RestAuthorizationManager, WcfWebHttpIISHostingSample"/>  
  8.   </behavior>  
  9. </serviceBehaviors>  
Now I have to extend the class ServiceAuthorizationManager with a custom class RestAuthorizationManager which I named it to make sense with the context.
  1. public class RestAuthorizationManager: ServiceAuthorizationManager  
  2. {  
  3.     /// <summary>  
  4.     /// Method source sample taken from here: http://bit.ly/1hUa1LR  
  5.     /// </summary>  
  6.     protected override bool CheckAccessCore(OperationContext operationContext)  
  7.     {  
  8.         //Extract the Authorization header, and parse out the credentials converting the Base64 string:  
  9.         var authHeader = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];  
  10.         if ((authHeader != null) && (authHeader != string.Empty))  
  11.         {  
  12.             var svcCredentials = System.Text.ASCIIEncoding.ASCII  
  13.                 .GetString(Convert.FromBase64String(authHeader.Substring(6)))  
  14.                 .Split(':');  
  15.             var user = new  
  16.             {  
  17.                 Name = svcCredentials[0], Password = svcCredentials[1]  
  18.             };  
  19.             if ((user.Name == "testuser" && user.Password == "testpassword"))  
  20.             {  
  21.                 //User is authrized and originating call will proceed  
  22.                 return true;  
  23.             }  
  24.             else  
  25.             {  
  26.                 //not authorized  
  27.                 return false;  
  28.             }  
  29.         }  
  30.         else  
  31.         {  
  32.             //No authorization header was provided, so challenge the client to provide before proceeding:  
  33.             WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"MyWCFService\"");  
  34.             //Throw an exception with the associated HTTP status code equivalent to HTTP status 401  
  35.             throw new WebFaultException(HttpStatusCode.Unauthorized);  
  36.         }  
  37.     }  
  38. }  
Now your application is ready to challenge any request with Basic Authentication. To test it you can use any client like Fiddler or Chrome’s post man plugin and see what outcome you get. Let’s simply make a request from normal browser I’ll get a challenge for basic authentication prompting user/password.
 
Authorization 
 
Enter the username - testuser and password – testpassword which we have used to validate the values in our RestAuthorizationManager class.
 
request  
 

Securing basic authentication credentials using SSL over Http i.e. (Https)

 
The Basic authentication information usually sent in plain text (encrypted by Base64 string which can be easily decrypted) over the network. Most of the browser issues a warning about this secure information being sent as plain text. If you try to launch the API call in IE browser you’ll see a warning something like the following:
 
window security 
 
Here comes the Transport layer security into picture. All communication being done over the network can be secured using the Transport layer security by using SSL(Secure Sockets Layer) certificates.
 
To apply SSL security first you need a certificate. In order to get a real certificate one can go to certificates providers such as Thawte, digicert, Godaddy, etc. and purchase a certificate. These providers (not mentioning any specific provider but all in general) are trusted providers for issuing digital certificates to ensure that identity of certificate owner is verified.
 
But in development environment you don’t need to purchase a SSL certificate in real. You can generate a local self-signed certificate from your machine. But the certificate would be only valid for your local use only. If you use the certificate over the network this would be invalidated. I’m not going into details, so let’s get started how to get a self-signed server certificate that you can use in development environment.
 

Creating a certificate and enabling the Https settings to use the certificate

 
You have two options either create a certificate using ‘makecert’ command. Here’s a nice detailed article with quite good explanation about certificates or you can use IIS 7.0 or greater to create your certificate. 
  1. Launch Internet Manager from the control panel or go to Run, then type ‘Inetmgr’ and press enter.

  2. Select the ROOT node on left side panel. Look for `Server Certificates` under `IIS` on right panel.

    click Server Certificates

  3. Double click on ‘Server Certificates’ and select ‘Create self-signed certificate’.

    Server Certificates

  4. Now enter the name of certificate. This will be the friendly name of your certificate.

    certificate

  5. Click Ok and certificate that you have created would appear in parent window.

  6. Now select the website you want to configure for HTTPS in IIS.

    edit site

  7. In the Site Bindings window, click Add.

    site building

  8. In the Add Site Binding window, enter the following information:

    Type: In the drop-down list, select https.
    IP address: In the drop-down list, select All Unassigned.
    Port: Enter 443. The port for SSL traffic is usually port 443.
    SSL certificate: In the drop-down list, select your recently imported SSL Certificate by its friendly name.

    edit site building

  9. Click OK. Your SSL Certificate is now installed and the website is configured to accept secure connections.

    Note: You may have to restart IIS or the server for it to recognize the new certificate (in some cases).

  10. To test the setting open the site binding again and select Https binding and click on ‘Browser’. You might see the following error.

    error

  11. To get rid of this error use the machine name exactly same as your certificate section “Issued to” says. For example, if you open your certificate then you’ll see issued to property and which should be your Machine name. If your machine is part of a domain then machine name would be like <machinename>.<xyz>.<domain> etc, so if you open it in your browser will fully qualified name of your machine then you won’t be getting that error.

    iis7

Setting up WCF REST service to use SSL (Https)

 
To enable the SSL over Http protocol follow the below steps:
  1. Add Protocol mapping for the webHttpBinding to use https.
    1. <protocolMapping>  
    2.    <add binding="webHttpBinding" scheme="https"/>  
    3. </protocolMapping>  
  2. Under binding -> webhttpbindings enable security mode Transport.
    1. <bindings>  
    2.       <webHttpBinding>  
    3.          <security mode="Transport" />  
    4.         </binding>  
    5.       </webHttpBinding>  
    6.  </bindings>  
  3. Add a host base address under services -> service.
    1. <service name="WcfWebHttpIISHostingSample.TestService" behaviorConfiguration="ServiceBehavior">  
    2.      <host>  
    3.       <baseAddresses>  
    4.         <add baseAddress="https://desktop-pc.mydomain/WcfWebHttpIISHostingSample/api/"/>  
    5.       </baseAddresses>  
    6.      </host>  
    7. …  
    8. …  
    9. </services>  
  4. Now rebuild the service and test it in the web browser. You will not see the warning of in-secure server communication any more.

    login
I hope this article helped you. Feel free to like and share. The complete sample used in this guide can be found here on Github.


Similar Articles