PostWizard - my first NuGet Package

For a while I have been fiddling around with session-less MVC3, the type of thing that can be easily load balanced. When you do this it would still be nice to be able to remember values between pages, and you'd think that some hidden html form fields would do trick nicely, but how could this be integrated with MVC? That is what I have been messing about with.  Adding a bit of JSON magic should make it even better.

So, I decided to release the result of my efforts somehow. A good chance to try out this NuGet thing :-) I guess.

I've called it 'PostWizard' and you can find it on NuGet here. I hope that it proves useful to somebody.

Creating MVC3 Razor views from a T4 Template

I blogged here about using T4 templates to inspect class properties. I also mentioned in passing that I had used it to create some MVC3 Razor views, so here is an example of that.

The process is essentially the same, except you need to change the output type from your template, like this:

<#@ output extension=".cshtml" #>

To get it to work on a basic model class you'll need to add some extra references, to allow the compiler to do its thing. I've allowed for that by passing in an array of assembly file names. So you can do something like this:

Parser p = new Parser(file, "T4RazorView.Models.HomeModel");
p.AddReferences = getReferences();

...and implement a method which returns them, something like this:

string[] getReferences()
{
   return new[] {
      "C:\\Program Files (x86)\\Microsoft ASP.NET
      \\ASP.NET MVC 3\\Assemblies\\System.Web.Mvc.dll",
      "System.Web.dll",
      "System.ComponentModel.DataAnnotations.dll",
   };
}

Which is all there is to it. If you add extra properties to the Model, the Razor View will automatically update. So here's an example MVC3 project in Visual Studio 2010 if you're interested.

More fiddling with MVC3 and https

I blogged here about securing logon cookies in MVC3. After writing a custom attribute based on the [RequireHttps] attribute it turned out that the best way was to use the forms authentication properties in web.config instead.

But the custom attribute that I wrote ended up morphing into something that solves a different problem. When you use the [RequireHttps] attribute, you might notice that even when a user logs out they continue with an https connection on subsequent requests to your site. This is not a big problem, but I find it annoying since https is not needed anymore. A similar thing might happen if a user has accidentally bookmarked the https version of your site's homepage, in which case the encryption might be unnecessary.

So I changed my existing attribute class into the [LimitHttps] Attribute. It checks to see if you are using a secure connection AND are not authenticated, then switches you back to plain old http - unless you are visiting a route that requires https. This is how I'm using it:

1) add the [RequireHttps] attribute to Account\LogOn and Account\Register
2) set up forms authentication with requireSSL="true" in web.config
3) add this line to RegisterGlobalFilters() in Global.asax:
     filters.Add(new LimitHttpsAttribute());

You'll now find that the following things happen:

- https will be enforced when a user is logged in
  (this is due to the requireSSL property in web.config)

- if a user manually goes back to http, the login cookie will not be sent in the request
  (also due to the requireSSL property)

- The LogOn and Register views in the Account controller will always use SSL (https)
  (because we've added the [RequireHttps] attribute to them)

- when a user logs out, they will automatically revert back to http
  (which is done by the [LimitHttps] attribute we've added)

- if a user visits the homepage with https they will switch back to http
  (the [LimitHttps] attribute does this too)

The code can be downloaded by clicking below.
Download the [LimitHttps] attribute

MVC3 caching refactored

I was using this code here when doing some testing, but essentially the code looks like this: 

public static class CacheExtensions
{
    public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator)
    {
        var result = cache[key];
        if (result == null)
        {
            result = generator();
            cache[key] = result;
        }
        return (T)result;
    }
}

...but I realised that it wasn’t actually doing much in the way of processing, and I wondered if it could be written more compactly.  So this is what I came up with:

 

public static class CacheExtensions

{

    public static T GetOrStore<T>(this Cache cache, string key, Func<T> generator) where T: class

    {

        return (cache[key] ?? (cache[key] = generator())) as T;

    }
}

As an old C programmer, I still like it when things can be done in a single line of code.

 

Security for login cookies with ASP.Net MVC3

I was reading here about how it's a bad idea to log into your application using SSL (https) and then revert back to http for subsequent pages. If you do that then you'll send the authentication token over an unencrypted connection, which is a bad thing.

Whilst wondering if there was an easy way to solve that problem, I wrote some code to try and enforce a secure connection whenever the user was authenticated. So I wrote my own [RequireHttpsWhenAuthenticatedAttribute] which inherited from [RequireHttpsAttribute]. The idea was that you apply it to your whole site from your global.asax, and then https will *automatically* be turned on (and enforced) when users are logged in.

After posting that code, I got an e-mail from Andy Brown (thanks Andy) pointing out that if a logged in user switches to http by editing the address in their browser, the cookie will have already been posted back to the site by the time my new attribute is able to do anything. To be totally safe you'd have to assume that the cookie is already compromised at that point. I then realised that even if the site signs them out, the cookie could still be used by a hijacker until it times out.  For example, this article says “Even after the user has logged out of the application and the developer has called FormsAuthentication.SignOut, the authentication ticket remains valid until its time-to-live (TTL) expires, so it can be used by an attacker to impersonate another user.” 

So I went back to the drawing board to try and find an even better way.

In the end, the best option seems to be simply using this option when you set up forms authentication in your web.config:

requireSSL="true"

Rather than refer to your whole site, this attribute just applies to the authentication cookie, meaning the the browser should only send the cookie over https. Using that setting does the same job that my code was trying to do, only better. So I don't need any special code after all.