Wednesday, April 27, 2011

Various Clients and Forms Authentication

Scenarios
In each of the below scenarios, forms authentication is used to secure access to the ASP.NET MVC endpoints and WCF services.
WPF accessing WCF services
WPF accessing MVC endpoints
Windows Phone 7 accessing WCF services
Desktop and mobile browsers accessing ASP.NET MVC website pages
jQuery accessing MVC endpoints
While I have not included the code for a Windows Phone 7 to access MVC endpoints that is a supported scenario as well.
Requirements
Visual Studio 2010
SQL Express 2008
Windows Phone 7 tools
If you don’t have these and don’t want to see this project, you can just remove the Windows Phone 7 project from the solution.

Background
I’ve been working on Stuff v2; a movie, game, and books application. Its primary use case is, "I’m at the store and don’t remember if I have a particular movie, game, or book. I need to determine if I have it; if not, then check the online price and ratings before making the purchase."
Given the varied application clients and devices, ASP.NET forms authentication seemed like the natural choice for authentication for the website, MVC3 JSON endpoints, and WCF services.
The reason I have varied client software and devices is more of a learning experience than an application requirement. I have other applications I want to write that will need to access the application from all my devices.

When I started programming the WPF client, I ran into a stone wall with respect to WPF accessing WCF services that are secured by forms authentication. This blog post is about getting over that stone wall.
Identifying the Problem Space
At the end of the day, the problem that needs solving is managing the forms authentication cookie or ticket.

Managing means, that after authenticating, the client must be able to retrieve the ticket returned in the response and include it in future requests to secured resources.
As you will see, client API’s vary across scenarios not only in coding patterns but in complexity as well.
Regardless of which client is accessing resources that require forms authentication, the following steps outline the required workflow:

Log in
Cache the ticket returned in the response
Include the ticket in subsequent requests
Setting up Forms Authentication
When I created the ASP.NET MVC3 application, VariousClients.Web, I used the MVC3 Internet template with the Razor view engine. This template sets up forms authentication and provides a pretty good out-of-box SQL Express membership system for you.
The below snippet from the web.config shows a few required changes:

<authentication mode="Forms">
    <!-- cookieless="UseCookies" is required by non-browser clients
                to authenticate using forms authentication-->
    <!-- production applications, change to requiresSSL="true"-->
    <forms timeout="2880" cookieless="UseCookies" loginUrl="~/Account/LogOn"
            requireSSL="false" />
</authentication>

Setting up the AuthenticationService
The System.Web.ApplicationServices.AuthenticationService is a built-in service that you can expose as a service endpoint on your website. This service exposes log in, log out methods for clients that access WCF endpoints requiring forms authentication. This service uses the membership provider defined in the web.config. After logging in, the service returns a ticket in the response, similar to forms authentication log in.
Adding the service is easy. First add a folder to the root of the website named, "Services". Into that folder, add a WCF service named Authentication.svc. Delete the generated service contract and code-behind files. Next replace the contents of the Authentication.scv file with the below code snippet.
<%@ ServiceHost Language="C#" Service="System.Web.ApplicationServices.AuthenticationService" %>

Now add the following to your web.config:

<system.web.extensions>
    <scripting>
        <webServices>
            <!-- for production applications, change to requiresSSL="true"-->
            <authenticationService enabled="true" requireSSL="false"/>
        </webServices>
    </scripting>
</system.web.extensions>

Rebuild your web application.
The Authentication.svc will now appear in the Add Service Reference dialog when adding service references in your client applications.

Read more: Karl on WPF