Forms authentication for all

By eidias on (tags: authentication, categories: code)

Earlier I wrote about the problems of a common authentication approach. Today, I’m going to do a quick demonstration how to set up forms authentication to secure a web app with an oData service and how to use forms authentication to connect to the service from a wpf client.

asp.net mvc

Setting up forms authentication for this one is pretty easy – File –> New Project –> asp.net mvc web application –> Internet Application (the first one, if you have SP1 installed). Done. Now that was easy :)

oData

Add an oData service to your mvc app (that would be the one named “WCF Data Service”). By default it’s not protected by any authentication, but all you need to do is some web.config changes. Add the following to your configuration:

   1: <?xml version="1.0"?>
   2: <system.web.extensions>
   3:     <scripting>
   4:         <webServices>
   5:             <authenticationService enabled="true" requireSSL="true"/>
   6:         </webServices>
   7:     </scripting>
   8: </system.web.extensions>

There’s just one thing that you need to keep in mind. The client (in our case the wpf application) cannot be built with “Client Profile” (e.g. .NET Framework 4.0 Client Profile) – that’s because the client profile does not contain some assemblies that are required to handle forms authentication (semi) automatically.

That doesn’t handle securing the service itself, so anyone is able to navigate to the service url and see what data it exposes. Of course, they won’t be able to query the data, but they will see what it is able to provide. In some situations, you don’t want to allow this, so another small piece of configuration can handle this

   1: <?xml version="1.0"?>
   2: <location path="Data.svc">
   3:     <system.web>
   4:         <authorization>
   5:             <deny users="?"/>
   6:         </authorization>
   7:     </system.web>
   8: </location>
   9:  

Just change the “Data.svc” to the service you have and you’re done.

WPF client

There are a couple of steps you need to take to enable forms authentication in a wpf app.

In project properties, on the “Application” tab, set the target framework NOT to use a client profile (so .Net Framework 4.0 instead of .Net Framework 4.0 Client Profile)

On the “Services” tab, check “enable client application services”, then select “Use forms authentication” and provide the url for the authentication service.

Now we need to make sure, that we send the authentication cookie with every request we make to the oData service. To do that, the DataServiceContext class (that was created when a service reference is added) needs to be extended. As the generated class is a partial one, create a file with the same name as the context class (and in the same namespace) and utilize the following code:

   1: public partial class ServiceContext
   2: {
   3:     partial void OnContextCreated()
   4:     {
   5:         SendingRequest += OnSendingRequest;
   6:     }
   7:  
   8:     private void OnSendingRequest(object sender, SendingRequestEventArgs e)
   9:     {
  10:         var identity = Thread.CurrentPrincipal.Identity;
  11:         if (identity is ClientFormsIdentity)
  12:             ((HttpWebRequest) e.Request).CookieContainer = ((ClientFormsIdentity) identity).AuthenticationCookies;
  13:     }
  14: }

With that set, if you want to log a user in use the following:

   1: if (Membership.ValidateUser("username", "password"))
   2: {
   3:     // authentication successful
   4: }
   5: else
   6: {    
   7:     // authentication failed
   8: }

If you want to log a user out:

   1: var authProvider = (ClientFormsAuthenticationMembershipProvider) Membership.Provider; 
   2: authProvider.Logout();

In some cases, you don’t want to be using the “Client Application Services” – no worries, there are ways to make the whole thing work. Here’s a nice article about that.

 
Cheers