Sunday, October 30, 2011

Creating a secure RESTfull wcf service and consume it cross domain with jquery using basic authentication

Last week I was very busy trying to create a secure wcf service which can be consumed using jquery jquery and wcf. There are a lot of resources (see References below) but none of them contain the full working package. Below I try to highlight the steps of creating the service and consumer. And because a sample says more than a thousand words, you can download it here.

Note:
The solution only works when the wcf service is hosted using iis. I have not tried to create the service using the self-hosting feature of wcf.


Note 2:
For basic authentication to be secure, you need to access it using SSL.


Step 1. Create your basic interface using the WebGet and WebInvoke
[OperationContract]
[WebGet(UriTemplate = "get/Do/{echo}", ResponseFormat = WebMessageFormat.Json)]
DoResponse Do(string echo);

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "post/Do/{echo}", ResponseFormat = WebMessageFormat.Json)]
DoResponse DoPost(string echo);


Step 2. Enable cross domain calls using the global.asax
protected void Application_BeginRequest(object sender, EventArgs e)
{
    EnableCrossDomainAjaxCall();
}

private void EnableCrossDomainAjaxCall()
{
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
        HttpContext.Current.Response.End();
    }
}


Step 3. Configure the basic html module
<bindings>
    <webHttpBinding>
        <binding name="BasicAuthentication">
            <security mode="TransportCredentialOnly">
                <transport clientCredentialType="Basic" />
            </security>
        </binding>
    </webHttpBinding>
</bindings>

<serviceBehaviors>
<behavior>
    <!-- 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"/>
    <serviceAuthorization serviceAuthorizationManagerType="WcfSampleApp.Wcfservice.BasicAuthorization, WcfSampleApp.Wcfservice" />
</behavior>
</serviceBehaviors>


Step 4. Call the service using jquery ajax using basic authentication header.
$.ajax( {
 url : 'http://localhost:35461/SampleApp.svc/get/Do/same problem',
 dataType: 'json',
 type: "GET",
 beforeSend : function(xhr) {
     xhr.setRequestHeader("Authorization", "Basic " + encodeBase64("sameproblem:morecode"));
 },
 error : function(xhr, ajaxOptions, thrownError) {
     $('#GetDiv').html("error");
 },
 success : function(model) {
     $("#GetDiv").html(model.Echo);
 }
});


Download example solution

References:
http://msdn.microsoft.com/en-us/library/dd203052.aspx
http://stackoverflow.com/questions/1640391/how-do-i-make-a-jsonp-call-with-jquery-with-basic-authentication
http://blog.rassemblr.com/2011/05/jquery-ajax-and-rest-http-basic-authentication-done-deal/
http://www.codeproject.com/KB/ajax/jQueryWCFRest.aspx
http://msdn.microsoft.com/en-us/magazine/cc948343.aspx
http://weblogs.asp.net/cibrax/archive/2009/03/20/custom-basic-authentication-for-restful-services.aspx