Windows Phone 7 and WCF REST – Authentication Solutions

by Ishai Hachlili 18. February 2011 13:31

I’ve been scouring the internets looking for a simple solution for authentication with WP7.
I am using a simple WCF REST web service based on the template for .net 4.0

Here are the two solutions I ended up with:

Solution 1 – Use the built in authentication service

Add a new WCF service to your project, remove the code behind file and change the svc file to this: 
<%@ ServiceHost Language="C#" Debug="true" Service="System.Web.ApplicationServices.AuthenticationService" %>

Add the forms authentication and membership configuration (just like any asp.net website)

Now in the WP7 project, you can add a service reference, again, this part is very standard.
To get this working, you need to use the cookie container on calls to both services.

Instead of detailing this approach, I figured I’ll just link to Kevin Hoffman’s blog post

Solution 2 – Use basic authentication

This solution is a lot more restful. There’s no state saved on the server, no session and no cookies.

I’ve decided to use RestSharpfor server calls from WP7.
It’s very easy to ad basic authentication code on the client side when using RestSharp since the library has built in support for it using the HttpBasicAuthenticator.

            var request = new RestRequest("Orders");
            request.Method = Method.GET;
            request.RequestFormat = DataFormat.Json;
            var client = new RestClient(baseUrl);
            client.Authenticator = new HttpBasicAuthenticator(userName, password);
            client.ExecuteAsync(request, (response) =>
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    //deal with the response
                }
            });

What I like about RestSharp is being able to define my resource. To get authentication working, I just needed one line of additional code on the client side.

So far, I’m sending the basic auth base64 encoded header to the server, now I need to intercept it on the server side and authenticate the user.
To do that, I added a class that inherits from ServiceAuthorizationManager, here’s the code:

    public class BasicAuthorization : ServiceAuthorizationManager
    {
        protected override bool CheckAccessCore(OperationContext operationContext)
        {
            string authtext = HttpContext.Current.Request.Headers["Authorization"];
            //if (String.IsNullOrWhiteSpace(authtext))
                //return false;
            if (!String.IsNullOrWhiteSpace(authtext))
            {
                string[] decoded = DecodeFrom64(authtext.Replace("Basic ", String.Empty)).Split(':');
                string username = decoded[0];
                string password = decoded[1];

                if (Membership.ValidateUser(username, password))
                {

                    MembershipUser user = Membership.GetUser(username);
                    GenericIdentity identity = new GenericIdentity(user.UserName);
                    //RolePrincipal principal = new RolePrincipal(identity);
                    GenericPrincipal principal = new GenericPrincipal(identity, "UserRole".Split(','));
                    System.Threading.Thread.CurrentPrincipal = principal;
                    HttpContext.Current.User = principal;
                    //return true;
                }
            }

            //always return true, we just want to get the identity set up so methods can support authorization
            return true;
        }

        /// <summary>
        /// The method to Decode your Base64 strings.
        /// </summary>
        /// <param name="encodedData">The String containing the characters to decode.</param>
        /// <returns>A String containing the results of decoding the specified sequence of bytes.</returns>
        private static string DecodeFrom64(string encodedData)
        {
            byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData);
            string returnValue = System.Text.Encoding.UTF8.GetString(encodedDataAsBytes);
            return returnValue;
        }
    }

There’s nothing complicated here, I’m just decoding the base64 string from the header and using the membership functions to validate the user’s credentials and create an IPrincipal object which is then set as the current user. This will allow methods in the actual service to access the membership object in a standard way. That’s also the reason the method always returns true. I’m not interested in blocking access at this point, I’ll leave that up to individual methods. (If you wanted to secure the entire service for authenticated users, you could return the result of the ValidateUser call, I wanted to have a methods that can be called by anonymous users as well).

This sample doesn’t add the user’s actual roles, which will be easy to implement (just get the roles using the username and add to the principal)

The last step is to update the servicemodel configuration to use the BasicAuthorization class. Just find the default behavior for your REST service and add the ServiceAuthoization element.

<behavior name="">
    <serviceMetadata httpGetEnabled="true"/>
    <serviceDebug includeExceptionDetailInFaults="true"/>
    <serviceAuthorization serviceAuthorizationManagerType="SampleWCFRESTService.BasicAuthorization, SampleWCFRESTService" />
</behavior>

Now checking “HttpContext.Current.User.Identity.IsAuthenticated” in any method in the web service will work.

 

The problem with basic authentication

The problem of course, is sending user credentials with every request. Since I don’t want to send all of the requests over SSL due to performance issues (and I usually don’t really have to) I need a better solution.

The standard solution for this problem is to make the first call over SSL to an “Authenticate” resource, create a token and send it back to the client. From that point on you can send the token with subsequent requests.

To add support for a token, you can add another ServiceAuthorizationManager or just update the logic to check if the Authorization header starts with Basic or CustomName.
The encrypted token should include the username and password and you can add other elements to it (like expiration for example).

In my implementation, my Authentication resource andthe ServiceAuthotizationManager both use the same class to encrypt/decrypt the username and password and in that class I also check if the token has expired.

I decided to go with the second solution since it seems to be the standard way REST services are developed (sending user/pass and getting a token). I wouldn’t really want to deal with cookies and that solution might not be friendly to other platforms.

Tags: , , , , ,

Windows Phone 7 | WCF

Too many scripts will slow us down

by Ishai Hachlili 1. March 2009 09:01

I’ve been ‘away’ from this blog for a while. It’s been a very interesting year for me but I’ve been neglecting this blog for too long.

If you’ve read the previous posts, you can see I’m not a big fan of the Asp.Net postbacks and update panels. Too much information is sent back and forth for small actions that can be easily done in javascript.

As I’ve shown before, there are hugh performance benefits to using client side rendering in a web app. Instead of sending the entire HTML for every request, we load javascript code for creating that HTML once and after that we just send the data for subsequent requests.

One of the side effects of moving from server side rendering is that you start getting more and more javascript files. I’ve been using JQuery for a while, there are a lot of great plugins for JQuery, but loading all of those include files introduces some problems:

  1. More scripts = more requests = more loading time
  2. Managing includes can become messy

Using a Script Combiner to reduce the number of requests
Ideally you want to have only one js file and one css file, but you don’t want to have your files merged while you’re developing, a hugh file will be a pain to work with. The solution is to merge all the scripts into one big file later, either in the build process or at run time.
if you use the same scripts for all pages in your app (or if you have a one page app), merging during the build process is a good solution but I needed different files for different pages.

Asp.Net AJAX 3.5
If you’re using Asp.Net AJAX 3.5, achieving this is very simple. The scripts from Microsoft will already be combined by default and to add your own scripts all you need to do is include your scripts using the ScriptManager.

<asp:ScriptManager runat="server" ID="ScriptManager1" >
    <CompositeScript>
        <Scripts>
            <asp:ScriptReference Path="~/JScript1.js" />
            <asp:ScriptReference Path="~/JScript2.js" />
        </Scripts>
    </CompositeScript>
</asp:ScriptManager>

Script Combiner - The Other Solution
If you don’t use Asp.Net AJAX and don’t want those scripts loaded (or you’re still using 2.0) you can create your own handler to combine scripts.
Here’s a project I foundby Omar Al Zabir (Who wrote the excellent book Building a Web 2.0 Portal with ASP.NET 3.5 and co-founded PageFlakes)
You might want to change the way you decide which scripts to load, I use an xml configuration file to specify the location of each script file and which js files should be loaded based on the page name that’s passed to the handler. (I use the page name as the key for now). I also have a separate path for the minified version and the debug version, and based on a config I use the right one

<ClientScripts>
   <Script name=”jquery” minPath=”Scripts/JQuery/jquery.1.2.6.min.js” debugPath=”Scripts/JQuery/jquery.1.2.6.js”/>
   <Script name=”jqvalidation” minPath=”Scripts/JQuery/plugins/jquery.validate.min.js” debugPath=”Scripts/JQuery/plugins/jquery.validate.js”/>
</ClientScripts>
<Pages>
   <Page name=”home” Scripts=”jquery,jqvalidation” />
</Pages>

There are several benefits when using this custom handler

  • You can use it for css files too
  • It compresses the js files using gzip
  • The files are only read from the file system once and are then cached on the server for subsequent requests
  • You can easily add versioning to the handler and set client side caching to never expire.

Tags: ,

AJAX | Asp.Net | Javascript

Upgrading ASMX web services to WCF

by Ishai Hachlili 15. June 2008 09:21

There is a lot of information on the web on using WCF for JSON, but I figured I’ll writing something short on the way I use it.

When I decided to try WCF, the first thing I noticed was how simple it was to upgrade. All you need to do is add a new WCF Service to the web project, copy the code from the ASMX service, change the [ScriptService] to [ServiceCntract] and the [WebMethod] tags to [OperationContract] and add some definitions in the web.config file.
You’re supposed to use a separate Interface to define the service contract, but it’s not a must and you can add the tags to the actual class with the implementation.

The second thing I noticed is that I can get JSON by changing some configuration settings.
When I was working on the AJAX search page, WCF was not around (it was by the time I posted the series on it here). I used XSLT to transform data to JSON and arrays. It was another step I had to do on the server side but it’s worth it, JSON is smaller than XML and very easy to work with in JavaScript.
With WCF I just change a small definition and I get the results in JSON, no need for the XSLT transformation.

Another thing we get with WCF is Data Contracts. The way I’m using it in this sample, it’s pretty much the same as using the .Net AJAX GenerateScriptType.
All I had to do is add a [DataContract] tag to the class and [DataMember] tags to each property.
I think it’s better to define this on the exposed class itself instead of adding some register definition in a web service.

The attached project is the same search page sample with the WCF service. The changes to look for are:

  • The new DataService.svc file
  • The Entities.QueryParameters classes now have the DataContract tags
  • web.config has the new serviceModel section at the end, that defines the service as an HTTP JSON enabled service
  • default.aspx – the service defined in the ScriptManager was changed to the svc file and the path was updated in the javascript Search method

 

WcfAjaxSearchSample.rar (883.99 kb)

Tags: , ,

AJAX | Asp.Net | WCF

About Me

Ishai Hachlili is a web and mobile application developer.

Currently working on Play The Hunt and The Next Line


Recent Tweets

Twitter October 23, 05:22
@BenThePCGuy a standard where that doesn't matter is better. One more reason to get the #Lumia920, wireless charging, no need for microUSB

Twitter October 23, 05:21
@ManMadeMoon where they dance around the issues and don't really talk about them

Twitter October 23, 05:20
@BenThePCGuy are you a @wpdev ?

Twitter October 23, 04:17
@JonahLupton But if it's black it's usually better

Twitter October 23, 02:58
@jongalloway next time ask your 5 year old how to spell

@EShy