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

5 comments:

  1. I am unable to setup the code you provided. Could you please provide some documentation on how to setup and test. I am using vs2010, IIS 7.5, windows 7. I have also IIS express installed.

    Thanks
    Venkat

    ReplyDelete
  2. Hi Venkat,

    To start, right click on SampleApp.svc and click 'View in browser'. You'll see an message showing up 'Basic Authentication Required'. Now run the Mvc.Test project, and you can see that the data returned by the webservice is during a get: 'same problem' and the post: 'more code'.

    In my setup both projects use IIS Express.

    ReplyDelete
  3. Hi Luuk

    Thanks for responding. I got the following response "This service requires basic authentication" when I view in browser the .svc file.

    When I run the MVC.Test project, the Get and Post, both response as "Error". Do I need to do something with IISExpress site config?

    Thanks
    Venkat

    ReplyDelete
    Replies
    1. Well, I think I am facing Crossdomain issue. Here is what I did. I add a .htm page and copy the Jquery from Index.cshtml page and also the jquery and base64 js files to the same service project and did view in browser and it works. I get the response "Getting: same problem" and "Posting:more code".

      I did a new webapp and copied the same htm page as wellas js files, I am getting an error. When I looked at xhr.StatusText - I see "No transport".

      Delete
    2. You can try to change the dataType in the ajax call to 'jsonp' in the WcfTest site. Then add 'crossDomainScriptAccessEnabled="true"' to the line with 'binding name="BasicAuthentication"' to the web.config in the WcfService. This adds special javascript crossdomain features. My VS is currently not working, so I can't test it right now.

      Delete